This commit is contained in:
2025-09-09 09:36:29 +08:00
62 changed files with 3535 additions and 2090 deletions

View File

@ -5,14 +5,15 @@ VITE_APP_TITLE = 煤科建管平台
VITE_APP_ENV = 'development'
# 开发环境
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 李陈杰 209
# VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# 曾涛
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 罗成
# VITE_APP_BASE_API = 'http://192.168.110.188:8899'
# 朱银
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# VITE_APP_BASE_API = 'http://192.168.110.149:8899'
#曾涛
# VITE_APP_BASE_API = 'http://192.168.110.171:8899'

View File

@ -0,0 +1 @@

View File

@ -101,3 +101,11 @@ export function getProjectId() {
method: 'get'
});
}
export const getFootNote = (data) => {
return request({
url: 'gps/equipmentSon/getList',
method: 'get',
data: data
});
};

View File

@ -0,0 +1,27 @@
import request from '@/utils/request';
//获取出库材料得列表
export const outboundMaterials = (query?: any) => {
return request({
url: '/materials/materials/listRelevancy',
method: 'get',
params: query
});
};
//新增出库
export const addOutbound = (data?: any) => {
return request({
url: '/materials/materialsInventory',
method: 'post',
data
});
};
//获取材料列表
export const getMaterialsList = (query?: any) => {
return request({
url: '/materials/materials/list',
method: 'get',
params: query
});
};

View File

@ -61,3 +61,13 @@ export const delMaterialsInventory = (id: string | number | Array<string | numbe
method: 'delete'
});
};
//获取新的列表数据
export const getLedgerList = (query?: any) => {
return request({
url: '/materials/materials/listUseDetail',
method: 'get',
params: query
});
};
//导出

View File

@ -33,7 +33,6 @@ export interface MaterialsUseRecordVO {
* 备注
*/
remark: string;
}
export interface MaterialsUseRecordForm extends BaseEntity {
@ -71,11 +70,9 @@ export interface MaterialsUseRecordForm extends BaseEntity {
* 备注
*/
remark?: string;
}
export interface MaterialsUseRecordQuery extends PageQuery {
/**
* 项目ID
*/
@ -105,7 +102,5 @@ export interface MaterialsUseRecordQuery extends PageQuery {
* 日期范围参数
*/
params?: any;
materialsId?: string | number;
}

View File

@ -8,7 +8,7 @@ import { MonthPlanVO, MonthPlanForm, MonthPlanQuery } from '@/api/out/monthPlan/
* @returns {*}
*/
export const listMonthPlan = (query?: MonthPlanQuery): AxiosPromise<MonthPlanVO[]> => {
export const listMonthPlan = (query?: any) => {
return request({
url: '/out/monthPlan/list',
method: 'get',
@ -93,7 +93,7 @@ export const isSubmit = (id): AxiosPromise => {
*/
export const getMonthInfo = (query): AxiosPromise<MonthPlanVO> => {
return request({
url: '/out/monthPlan/monthInfo',
url: '/out/monthPlan/monthInfo/' + query.id,
method: 'get',
params: query
});

View File

@ -8,10 +8,11 @@ import { ProgressCategoryVO, ProgressCategoryForm, ProgressCategoryQuery } from
* @returns {*}
*/
export const listProgressCategory = (id?: string | number): AxiosPromise<any[]> => {
export const listProgressCategory = (parentId?: string | number,name?:string): AxiosPromise<any[]> => {
return request({
url: '/progress/progressCategory/listByParent/' + id,
method: 'get'
url: '/progress/progressCategory/listByParent',
method: 'get',
params:{parentId,name}
});
};

View File

@ -78,9 +78,10 @@ export const getTabList = (id: string) => {
* @param parentId
* @returns {*}
*/
export const listProgressCategoryTemplateByParent = (parentId: string | number): AxiosPromise<ProgressCategoryTemplateVO[]> => {
export const listProgressCategoryTemplateByParent = (parentId: string | number,name:string): AxiosPromise<ProgressCategoryTemplateVO[]> => {
return request({
url: '/progress/progressCategoryTemplate/listByParent/' + parentId,
method: 'get'
url: '/progress/progressCategoryTemplate/listByParent' ,
method: 'get',
params:{parentId,name}
});
};

View File

@ -164,7 +164,7 @@ export const updateConstructionUserSalary = (data: ConstructionUserSalaryForm) =
*/
export const getConstructionUserExit = (query: ConstructionUserExitForm) => {
return request({
url: '/contractor/constructionUserExit/list',
url: '/project/constructionUserExit/list',
method: 'get',
params: query
});
@ -204,7 +204,6 @@ export const importConstructionUserInfo = (file: string) => {
});
};
// 获取项目列表
export const ProjectList = (query) => {
return request({

View File

@ -10,7 +10,7 @@ import { ConstructionUserFileVO, ConstructionUserFileForm, ConstructionUserFileQ
export const listConstructionUserFile = (query?: ConstructionUserFileQuery): AxiosPromise<ConstructionUserFileVO[]> => {
return request({
url: '/project/constructionUserFile/list',
url: '/contractor/constructionUserFile/list',
method: 'get',
params: query
});
@ -22,7 +22,7 @@ export const listConstructionUserFile = (query?: ConstructionUserFileQuery): Axi
*/
export const setConstructionUserFile = (data: ConstructionUserFileForm): AxiosPromise<string | number> => {
return request({
url: '/project/constructionUserFile/save',
url: '/contractor/constructionUserFile/save',
method: 'post',
data
});
@ -34,7 +34,7 @@ export const setConstructionUserFile = (data: ConstructionUserFileForm): AxiosPr
*/
export const delConstructionUserFile = (id: string | number | Array<string | number>) => {
return request({
url: '/project/constructionUserFile/' + id,
url: '/contractor/constructionUserFile/' + id,
method: 'delete'
});
};

View File

@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { QuestionBankVO, QuestionBankForm, QuestionBankQuery } from '@/api/safety/questionBank/types';
import { QuestionBankVO, QuestionBankForm, QuestionBankQuery } from '@/api/safety/wgzQuestionBank/types';
/**
* 查询题库列表
@ -10,7 +10,7 @@ import { QuestionBankVO, QuestionBankForm, QuestionBankQuery } from '@/api/safet
export const listQuestionBank = (query?: QuestionBankQuery): AxiosPromise<QuestionBankVO[]> => {
return request({
url: '/safety/questionBank/list',
url: '/safety/wgzQuestionBank/list',
method: 'get',
params: query
});
@ -22,7 +22,7 @@ export const listQuestionBank = (query?: QuestionBankQuery): AxiosPromise<Questi
*/
export const getQuestionBank = (id: string | number): AxiosPromise<QuestionBankVO> => {
return request({
url: '/safety/questionBank/' + id,
url: '/safety/wgzQuestionBank/' + id,
method: 'get'
});
};
@ -33,7 +33,7 @@ export const getQuestionBank = (id: string | number): AxiosPromise<QuestionBankV
*/
export const addQuestionBank = (data: QuestionBankForm) => {
return request({
url: '/safety/questionBank',
url: '/safety/wgzQuestionBank',
method: 'post',
data: data
});
@ -45,7 +45,7 @@ export const addQuestionBank = (data: QuestionBankForm) => {
*/
export const updateQuestionBank = (data: QuestionBankForm) => {
return request({
url: '/safety/questionBank',
url: '/safety/wgzQuestionBank',
method: 'put',
data: data
});
@ -57,7 +57,7 @@ export const updateQuestionBank = (data: QuestionBankForm) => {
*/
export const delQuestionBank = (id: string | number | Array<string | number>) => {
return request({
url: '/safety/questionBank/' + id,
url: '/safety/wgzQuestionBank/' + id,
method: 'delete'
});
};

View File

@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { QuestionUserAnswerVO, QuestionUserAnswerForm, QuestionUserAnswerQuery } from '@/api/safety/questionUserAnswer/types';
import { QuestionUserAnswerVO, QuestionUserAnswerForm, QuestionUserAnswerQuery } from '@/api/safety/wgzQuestionSave/types';
/**
* 查询用户试卷存储列表
@ -10,7 +10,7 @@ import { QuestionUserAnswerVO, QuestionUserAnswerForm, QuestionUserAnswerQuery }
export const listQuestionUserAnswer = (query?: QuestionUserAnswerQuery): AxiosPromise<QuestionUserAnswerVO[]> => {
return request({
url: '/safety/questionUserAnswer/list',
url: '/safety/wgzQuestionSave/list',
method: 'get',
params: query
});
@ -22,7 +22,7 @@ export const listQuestionUserAnswer = (query?: QuestionUserAnswerQuery): AxiosPr
*/
export const getQuestionUserAnswer = (id: string | number): AxiosPromise<QuestionUserAnswerVO> => {
return request({
url: '/safety/questionUserAnswer/' + id,
url: '/safety/wgzQuestionSave/' + id,
method: 'get'
});
};
@ -33,7 +33,7 @@ export const getQuestionUserAnswer = (id: string | number): AxiosPromise<Questio
*/
export const addQuestionUserAnswer = (data: QuestionUserAnswerForm) => {
return request({
url: '/safety/questionUserAnswer',
url: '/safety/wgzQuestionSave',
method: 'post',
data: data
});
@ -45,7 +45,7 @@ export const addQuestionUserAnswer = (data: QuestionUserAnswerForm) => {
*/
export const updateQuestionUserAnswer = (data: QuestionUserAnswerForm) => {
return request({
url: '/safety/questionUserAnswer',
url: '/safety/wgzQuestionSave',
method: 'put',
data: data
});
@ -57,7 +57,7 @@ export const updateQuestionUserAnswer = (data: QuestionUserAnswerForm) => {
*/
export const delQuestionUserAnswer = (id: string | number | Array<string | number>) => {
return request({
url: '/safety/questionUserAnswer/' + id,
url: '/safety/wgzQuestionSave/' + id,
method: 'delete'
});
};
@ -68,7 +68,7 @@ export const delQuestionUserAnswer = (id: string | number | Array<string | numbe
*/
export const uploadQuestionUserAnswer = (data: any) => {
return request({
url: '/safety/questionUserAnswer/upload/zip',
url: '/safety/wgzQuestionSave/upload/zip',
method: 'post',
data: data
});

View File

@ -10,7 +10,7 @@ import { QuestionsCategoryVO, QuestionsCategoryForm, QuestionsCategoryQuery } fr
export const listQuestionsCategory = (query?: QuestionsCategoryQuery): AxiosPromise<QuestionsCategoryVO[]> => {
return request({
url: '/safety/questionsCategory/list',
url: '/safety/wzgQuestionCategory/list',
method: 'get',
params: query
});
@ -22,7 +22,7 @@ export const listQuestionsCategory = (query?: QuestionsCategoryQuery): AxiosProm
*/
export const getQuestionsCategory = (id: string | number): AxiosPromise<QuestionsCategoryVO> => {
return request({
url: '/safety/questionsCategory/' + id,
url: '/safety/wzgQuestionCategory' + id,
method: 'get'
});
};
@ -33,7 +33,7 @@ export const getQuestionsCategory = (id: string | number): AxiosPromise<Question
*/
export const addQuestionsCategory = (data: QuestionsCategoryForm) => {
return request({
url: '/safety/questionsCategory',
url: '/safety/wzgQuestionCategory',
method: 'post',
data: data
});
@ -45,7 +45,7 @@ export const addQuestionsCategory = (data: QuestionsCategoryForm) => {
*/
export const updateQuestionsCategory = (data: QuestionsCategoryForm) => {
return request({
url: '/safety/questionsCategory',
url: '/safety/wzgQuestionCategory',
method: 'put',
data: data
});
@ -57,7 +57,7 @@ export const updateQuestionsCategory = (data: QuestionsCategoryForm) => {
*/
export const delQuestionsCategory = (id: string | number | Array<string | number>) => {
return request({
url: '/safety/questionsCategory/' + id,
url: '/safety/wzgQuestionCategory' + id,
method: 'delete'
});
};

View File

@ -22,7 +22,7 @@ export const listQuestionsConfig = (query?: QuestionsConfigQuery): AxiosPromise<
*/
export const getQuestionsConfig = (id: string | number): AxiosPromise<QuestionsConfigVO> => {
return request({
url: '/safety/questionsConfig/' + id,
url: '/safety/wzgQuestionsConfiguration/' + id,
method: 'get'
});
};
@ -45,7 +45,7 @@ export const addQuestionsConfig = (data: QuestionsConfigForm) => {
*/
export const updateQuestionsConfig = (data: QuestionsConfigForm) => {
return request({
url: '/safety/questionsConfig',
url: '/safety/wzgQuestionsConfiguration',
method: 'put',
data: data
});

View File

@ -79,3 +79,26 @@ export const landTransferLedgerCount = (id: string | number | Array<string | num
method: 'get'
});
};
export const addSonLandTransferLedger = (data) => {
return request({
url: '/land/landTransferLedger/children/add',
method: 'post',
data: data
});
};
export const listSonLandTransferLedger = (query) => {
return request({
url: '/land/landTransferLedger/children/list',
method: 'get',
params: query
});
};
// api/yourApiModule.js
export const listallCountValue = (projectId) => {
return request({
url: '/land/landTransferLedger/allCountValue/' + projectId,
method: 'get'
});
};

View File

@ -4,6 +4,11 @@ export interface LandTransferLedgerVO {
*/
id: string | number;
/**
* 父级ID
*/
parentId: string | number;
/**
* 项目ID
*/
@ -83,7 +88,6 @@ export interface LandTransferLedgerVO {
* 下一步策略
*/
nextStrategy: string;
}
export interface LandTransferLedgerForm extends BaseEntity {
@ -92,6 +96,11 @@ export interface LandTransferLedgerForm extends BaseEntity {
*/
id?: string | number;
/**
* 父级ID
*/
parentId: string | number;
/**
* 项目ID
*/
@ -171,11 +180,9 @@ export interface LandTransferLedgerForm extends BaseEntity {
* 下一步策略
*/
nextStrategy?: string;
}
export interface LandTransferLedgerQuery extends PageQuery {
/**
* 项目ID
*/
@ -261,6 +268,3 @@ export interface LandTransferLedgerQuery extends PageQuery {
*/
params?: any;
}

View File

@ -203,6 +203,7 @@ watch(
});
} else {
fileList.value = [];
return [];
}
},
@ -293,7 +294,7 @@ const handleChange = (file: any, filelist: any) => {
}
}
// 记录 status = 'ready' 的文件
if (file.status === 'ready') {
if (file.status === 'ready' && !props.isConstruction) {
pendingFiles.value.push(file);
fileList.value = pendingFiles.value;
}

View File

@ -201,6 +201,8 @@ const uploadedSuccessfully = () => {
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
uploadList.value = [];
number.value = 0;
console.log(fileList.value);
emit('update:modelValue', listToString(fileList.value));
proxy?.$modal.closeLoading();
}

View File

@ -170,8 +170,6 @@ onMounted(() => {
//分页
const getWaitingList = () => {
pageByTaskWait({ pageNum: 1, pageSize: 10 }).then((resp) => {
console.log(resp);
total.value = resp.total;
});
};

View File

@ -7,6 +7,7 @@
<template #title>
<span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
<span class="bage" v-if="onlyOneChild.meta?.title == '我的待办' && total > 0">{{ total }}</span>
<span class="bage" v-if="onlyOneChild.meta?.title == '我的抄送' && totalChao > 0">{{ totalChao }}</span>
</template>
</el-menu-item>
</app-link>
@ -16,7 +17,7 @@
<template v-if="item.meta" #title>
<svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
<span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
<!-- <span class="bage" v-if="item.meta?.title == '我的任务' && total >= 0">{{ total }}</span> -->
<span class="bage" v-if="item.meta?.title == '我的任务' && total > 0">{{ total }}</span>
</template>
<sidebar-item
@ -36,7 +37,7 @@ import { isExternal } from '@/utils/validate';
import AppLink from './Link.vue';
import { getNormalPath } from '@/utils/ruoyi';
import { RouteRecordRaw } from 'vue-router';
import { pageByTaskWait } from '@/api/workflow/task';
import { pageByTaskWait, pageByTaskCopy } from '@/api/workflow/task';
import useUserStore from '@/store/modules/user';
import useNoticeStore from '@/store/modules/notice';
const userStore = useUserStore();
@ -56,21 +57,27 @@ const props = defineProps({
}
});
const total = ref(0);
const totalChao = ref(0);
onMounted(() => {
if (onlyOneChild.value.meta?.title == '我的待办' || props.item.meta?.title == '我的任务') {
console.log(44444444);
getWaitingList();
}
if (onlyOneChild.value.meta?.title == '我的抄送') {
getChaoList();
}
});
// 获取我的待办
//分页
const getWaitingList = () => {
pageByTaskWait({ pageNum: 1, pageSize: 10 }).then((resp) => {
console.log(resp);
total.value = resp.total;
});
};
// 获取我的抄送
const getChaoList = () => {
pageByTaskCopy({ pageNum: 1, pageSize: 10 }).then((resp) => {
totalChao.value = resp.total;
});
};
const onlyOneChild = ref<any>({});
const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
@ -123,9 +130,7 @@ const hasTitle = (title: string | undefined): string => {
watch(
() => noticeStore.state.value.notices,
(newVal) => {
if (onlyOneChild.value.meta?.title == '我的待办') {
console.log(121212121);
if (onlyOneChild.value.meta?.title == '我的待办' || props.item.meta?.title == '我的任务') {
let time = setTimeout(() => {
getWaitingList();
clearTimeout(time);

View File

@ -62,7 +62,8 @@
</div>
<div v-for="item in teamAttendanceList" :key="item.id" class="attendance_item">
<div class="attendance_item_title">{{ item.teamName }}</div>
<div class="attendance_item_number">{{ item.attendanceNumber }} <span class="subfont">/{{ item.allNumber }}</span></div>
<div class="attendance_item_number">{{ item.attendanceNumber }} <span class="subfont">/{{ item.allNumber
}}</span></div>
<div class="attendance_item_rate">{{ item.attendanceRate }} %</div>
<div class="attendance_item_date subfont">{{ item.attendanceTime }}</div>
</div>
@ -247,12 +248,13 @@ onUnmounted(() => {
margin-top: 15px;
.tag_item {
width: 28%;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
border: 1px dashed rgba(29, 214, 255, 0.3);
padding: 10px 25px;
padding: 10px;
.tag_info {
font-size: 20px;

View File

@ -173,19 +173,20 @@ onUnmounted(() => {
.chart_container {
display: flex;
flex-direction: column;
gap: 5px;
width: 100%;
height: 100%;
}
.echart {
height: 50%;
height: 48%;
width: 100%;
}
}
}
.content {
max-height: 100px;
height: 100px;
margin: 0 15px;
padding: 0 10px;
margin-top: 15px;

View File

@ -57,8 +57,8 @@
</transition>
<el-card shadow="never" class="mb8">
<el-table ref="tableRef" v-loading="loading" :data="tableData" row-key="id" border lazy default-expand-all>
<el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="工程或费用名称" />
<el-table-column prop="num" label="编号" align="center" />
<el-table-column prop="name" label="工程或费用名称" align="center" />
<el-table-column prop="unit" label="单位" align="center" />
<el-table-column prop="specification" label="规格" align="center" />
<el-table-column prop="quantity" label="数量" align="center">
@ -262,7 +262,7 @@ const importExcel = (options: any): any => {
let formData = new FormData();
formData.append('file', options.file);
loading.value = true;
BiddingImportExcelFile({ projectId: currentProject.value?.id }, formData)
BiddingImportExcelFile({ projectId: currentProject.value?.id, versions: queryForm.value.versions }, formData)
.then((res) => {
const { code } = res;
if (code == 200) {

View File

@ -23,13 +23,19 @@
{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" />
<el-table-column prop="content" label="内容" />
<el-table-column prop="price" label="限价" />
<el-table-column prop="name" label="名称" align="center" />
<el-table-column prop="content" label="内容" align="center" />
<el-table-column prop="price" label="限价" align="center" />
<el-table-column prop="plannedBiddingTime" align="center">
<template #header> <span style="color: red">*</span>计划招标时间 </template>
<template #default="scope">
<el-date-picker v-model="scope.row.plannedBiddingTime" type="date" value-format="YYYY-MM-DD" placeholder="选择时间" />
<el-date-picker
v-model="scope.row.plannedBiddingTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择时间"
:disabled="scope.row.status == 0"
/>
</template>
</el-table-column>
<el-table-column prop="price" label="操作" align="center">
@ -143,9 +149,11 @@
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) ==
0
? ''
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
: (
(scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
).toFixed(2)
}}
</template>
</el-table-column>

View File

@ -24,7 +24,8 @@
</el-form-item>
<el-form-item label="合同类型" prop="contractType">
<el-select v-model="form.contractType" placeholder="请选择合同类型">
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label" :value="item.value" />
<el-option v-for="item in income_contract_type" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="业主单位" prop="contractOwner">
@ -37,17 +38,15 @@
<editor v-model="form.contractedContent" :min-height="192" />
</el-form-item>
<el-form-item label="合同金额" prop="amount">
<el-input
v-model="form.amount"
placeholder="请输入合同金额"
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
/>
<el-input v-model="form.amount" placeholder="请输入合同金额"
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="附件">
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef" :defaultFileList="tempFileList" />
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef"
:defaultFileList="tempFileList" />
</el-form-item>
</el-form>
</template>
@ -61,35 +60,36 @@
</el-form-item>
<el-form-item label="合同类型" prop="contractType">
<el-select v-model="form.contractType" placeholder="请选择合同类型">
<el-option v-for="item in expenses_contract_type" :key="item.value" :label="item.label" :value="item.value" />
<el-option v-for="item in expenses_contract_type" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="招标计划" prop="tenderId">
<!-- <el-input v-model="form.tenderId" placeholder="请输入招标Id" /> -->
<el-input v-model="form.name" placeholder="请选择招标计划" disabled />
<el-button type="primary" @click="handleChoose" v-hasPermi="['ctr:expensesContract:tenderList']">选择招标</el-button>
<el-button type="primary" @click="handleChoose"
v-hasPermi="['ctr:expensesContract:tenderList']">选择招标</el-button>
</el-form-item>
<el-form-item label="供应商" prop="contractSupplier">
<el-input v-model="form.contractSupplier" placeholder="请输入供应商" disabled />
</el-form-item>
<el-form-item label="分包内容">
<!-- <editor v-model="form.contractedContent" :min-height="192" disabled /> -->
<el-input v-model="form.contractedContent" style="width: 300px" :autosize="{ minRows: 2, maxRows: 4 }" type="textarea" disabled />
<el-input v-model="form.contractedContent" style="width: 300px" :autosize="{ minRows: 2, maxRows: 4 }"
type="textarea" disabled />
</el-form-item>
<el-form-item label="合同金额" prop="amount">
<el-input
oninput="value=value.replace(/[^0-9.]/g,'').replace(/\.{2,}/g,'.').replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3')"
v-model="form.amount"
placeholder="请输入合同金额"
disabled
/>
v-model="form.amount" placeholder="请输入合同金额" disabled />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="合同附件">
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef" :defaultFileList="tempFileList" />
<FileUpload :multiple="true" :fileType="['pdf']" :onUploadSuccess="onUploadSuccess" :ref="fileRef"
:defaultFileList="tempFileList" />
</el-form-item>
</el-form>
</template>
@ -280,7 +280,6 @@ const resetForm = () => {
};
fileList.value = [];
tempFileList.value = [];
contract_type.value = '';
setTimeout(() => {
localStorage.removeItem('tempContractForm');
}, 0);
@ -399,6 +398,7 @@ const getInfoByProjectIdList = async () => {
form.value.contractOwner = res.data.planDuration;
};
onMounted(() => {
contract_type.value = '';
getInfoByProjectIdList();
const tempForm = localStorage.getItem('tempContractForm');

View File

@ -47,9 +47,9 @@
<el-row :gutter="8" class="mb-3 font-medium text-gray-700 whitespace-nowrap">
<el-col :span="4">专业</el-col>
<el-col :span="5">设计人员可多选</el-col>
<el-col :span="5">校审人员</el-col>
<el-col :span="5">校审人员</el-col> <el-col :span="4">审核人员</el-col>
<el-col :span="5">审定人员</el-col>
<el-col :span="4">审核人员</el-col>
<el-col :span="3"></el-col>
</el-row>
@ -209,61 +209,7 @@
</el-col>
<!-- 4. 审定人员 -->
<el-col :span="5" class="mb-4 sm:mb-0">
<div class="pl-2 border-l-2 border-orange-200 py-2">
<div class="space-y-3">
<div
v-for="(person, personIndex) in majorConfig.approvedPersons"
:key="`approved-${configIndex}-${personIndex}`"
class="flex items-center"
>
<el-form-item
:prop="`approved.${configIndex}.persons.${personIndex}.userId`"
:rules="{ required: true, message: '请选择审定人员', trigger: 'change' }"
class="flex-1 mr-2 mb-0"
label="审定"
label-width="50px"
>
<el-select
filterable
v-model="person.userId"
placeholder="选择人员"
class="w-full transition-all duration-300 border-gray-300"
@change="() => checkDuplicate(person, 'approved', configIndex, personIndex)"
>
<el-option v-for="item in userList" :key="`user-${item.userId}`" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<!-- <div class="flex gap-1">
<el-button
type="danger"
size="small"
@click="removePerson('approved', configIndex, personIndex)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="majorConfig.approvedPersons.length <= 1 || disabledForm"
>
<el-icon :size="14"><Delete /></el-icon>
</el-button>
<el-button
type="success"
size="small"
@click="addPerson('approved', configIndex)"
class="transition-all duration-300 transform hover:scale-105"
:disabled="!form.designers[configIndex].userMajor || disabledForm"
>
<el-icon :size="14"><Plus /></el-icon>
</el-button>
</div> -->
</div>
</div>
<div
v-if="majorConfig.approvedPersons.length == 0"
class="text-gray-500 text-xs py-2 bg-gray-100 rounded border border-dashed border-gray-200"
>
点击"添加"
</div>
</div>
</el-col>
<!-- 5. 审核人员 -->
<el-col :span="5" class="mb-4 sm:mb-0">
@ -321,6 +267,61 @@
</div>
</div>
</el-col>
<el-col :span="5" class="mb-4 sm:mb-0">
<div class="pl-2 border-l-2 border-orange-200 py-2">
<div class="space-y-3">
<div
v-for="(person, personIndex) in majorConfig.approvedPersons"
:key="`approved-${configIndex}-${personIndex}`"
class="flex items-center"
>
<el-form-item
:prop="`approved.${configIndex}.persons.${personIndex}.userId`"
:rules="{ required: true, message: '请选择审定人员', trigger: 'change' }"
class="flex-1 mr-2 mb-0"
label="审定"
label-width="50px"
>
<el-select
filterable
v-model="person.userId"
placeholder="选择人员"
class="w-full transition-all duration-300 border-gray-300"
@change="() => checkDuplicate(person, 'approved', configIndex, personIndex)"
>
<el-option v-for="item in userList" :key="`user-${item.userId}`" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
<!-- <div class="flex gap-1">
<el-button
type="danger"
size="small"
@click="removePerson('approved', configIndex, personIndex)"
class="transition-all duration-300 hover:bg-red-600"
:disabled="majorConfig.approvedPersons.length <= 1 || disabledForm"
>
<el-icon :size="14"><Delete /></el-icon>
</el-button>
<el-button
type="success"
size="small"
@click="addPerson('approved', configIndex)"
class="transition-all duration-300 transform hover:scale-105"
:disabled="!form.designers[configIndex].userMajor || disabledForm"
>
<el-icon :size="14"><Plus /></el-icon>
</el-button>
</div> -->
</div>
</div>
<div
v-if="majorConfig.approvedPersons.length == 0"
class="text-gray-500 text-xs py-2 bg-gray-100 rounded border border-dashed border-gray-200"
>
点击"添加"
</div>
</div>
</el-col>
<!-- 操作列 -->
<el-col :span="2" class="pr-4 mt-2 text-right">
@ -343,13 +344,17 @@
type="primary"
size="large"
v-hasPermi="['design:user:batch']"
icon="Check"
@click="submitForm"
class="px-8 py-2.5 transition-all duration-300 transform hover:scale-105 bg-blue-500 hover:bg-blue-600 text-white font-medium"
>
<i class="el-icon-check mr-2"></i>确认提交
>确认提交
</el-button>
<el-button size="large" @click="resetForm" class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium">
<i class="el-icon-refresh mr-2"></i>重置
<el-button
size="large"
icon="Refresh"
@click="resetForm"
class="px-8 py-2.5 transition-all duration-300 border-gray-300 hover:bg-gray-100 font-medium"
>重置
</el-button>
</div>
</el-form>

View File

@ -93,11 +93,10 @@
>审核通知单</el-button
>
<el-button
v-if="scope.row.status != 'draft'"
v-if="scope.row.status != 'draft' || scope.row.auditStatus != 'draft'"
type="success"
link
icon="View"
v-hasPermi="['design:designChange:query']"
@click="handleViewDetail(scope.row)"
>查看通知单</el-button
>
@ -113,8 +112,7 @@
type="warning"
link
icon="View"
v-hasPermi="['design:drawingreviewReceipts:list']"
v-if="scope.row.status != 'draft'"
v-if="scope.row.status != 'draft' || scope.row.auditStatus != 'draft'"
@click="handleViewHistory(scope.row)"
>查看单据</el-button
>

View File

@ -62,13 +62,13 @@
:accept="'.xlsx,.xls'"
:limit="1"
>
<el-button type="primary" icon="Upload">导入文件</el-button>
<el-button type="primary" icon="Download">导入文件</el-button>
</el-upload>
<el-button
v-if="!form.id || form.status == 'draft'"
type="primary"
style="margin-left: 20px"
icon="Download"
icon="Upload"
@click="exportTemplate"
class="transition-all hover:bg-blue-600"
>

View File

@ -121,10 +121,10 @@
</div> -->
<div class="info-item">
<span class="info-label">更新时间</span>
<span class="info-label">上传时间</span>
<div class="info-value mt-0.5 flex items-center">
<i class="fa fa-calendar-o text-gray-400 dark:text-gray-500 mr-1.5"></i>
{{ info.updateTime || '未更新' }}
{{ info.createTime || '暂无' }}
</div>
</div>
</div>

View File

@ -68,6 +68,7 @@
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['design:volumeCatalog:listFile']"
>查看文件</el-button
>
<el-badge v-if="scope.row.fileCount" :value="scope.row.fileCount" class="item" type="danger"> </el-badge>
</template>
</el-table-column>
<el-table-column label="外部意见" align="center">
@ -153,8 +154,8 @@
<el-form-item v-if="uploadForm.type == '3'" label="蓝图" prop="fileIds">
<file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.fileIds"></file-upload>
</el-form-item>
<el-form-item v-if="uploadForm.type == '3'" label="抄送人">
<el-select multiple filterable clearable v-model="form.userIds" placeholder="请选择抄送人">
<el-form-item v-if="uploadForm.type == '3'" label="通知人">
<el-select multiple filterable clearable v-model="form.userIds" placeholder="请选择通知人">
<el-option :value="item.userId" v-for="item in userCoryList" :key="item.userId" :label="item.nickName + '-' + item.phonenumber" />
</el-select>
</el-form-item>
@ -171,8 +172,8 @@
<!-- 查看文件列表 -->
<el-dialog draggable title="图纸列表" v-model="viewVisible" width="1000px">
<el-tabs type="border-card" v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="蓝图" name="3"
><TableContent :data="fileList" :wf-business-status="wf_business_status">
<el-tab-pane label="蓝图" name="3">
<TableContent :data="fileList" :wf-business-status="wf_business_status">
<template #operation="{ row }">
<el-button
link
@ -195,10 +196,10 @@
>查看单据</el-button
>
</template>
</TableContent></el-tab-pane
>
<el-tab-pane label="过程图纸 " name="1"
><TableContent :data="fileList" :wf-business-status="wf_business_status">
</TableContent>
</el-tab-pane>
<el-tab-pane label="过程图纸 " name="1">
<TableContent :data="fileList" :wf-business-status="wf_business_status">
<template #operation="{ row }">
<el-button link type="primary" icon="edit" @click="handleAudit(row)" v-if="row.auditStatus == 'draft' || row.auditStatus == 'back'"
>审核</el-button
@ -216,15 +217,15 @@
>查看单据</el-button
>
</template>
</TableContent></el-tab-pane
>
<el-tab-pane label="作废 " name="4"
><TableContent :data="fileList" :wf-business-status="wf_business_status">
</TableContent>
</el-tab-pane>
<el-tab-pane label="作废 " name="4">
<TableContent :data="fileList" :wf-business-status="wf_business_status">
<template #operation="{ row }">
<el-button type="danger" link icon="Download" @click="handleDownload(row)"> 下载 </el-button>
</template>
</TableContent></el-tab-pane
>
</TableContent>
</el-tab-pane>
</el-tabs>
<template #footer>
<span>
@ -644,22 +645,29 @@ const getVolumeFileList = async (type) => {
}
};
const exportFile = () => {
// 导出模版文件
try {
// 创建a标签
const link = document.createElement('a');
// 设置PDF文件路径 - 相对于public目录
link.href = '/catalog.xlsx';
// 设置下载后的文件名
link.download = '设计出图计划导入模版.xlsx';
// 触发点击
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
} catch (error) {
alert('下载失败,请重试');
}
proxy?.download(
'/design/volumeCatalog/exportExcel',
{
projectId: currentProject.value?.id
},
`设计出图计划导入模版.xlsx`
);
// // 导出模版文件
// try {
// // 创建a标签
// const link = document.createElement('a');
// // 设置PDF文件路径 - 相对于public目录
// link.href = '/catalog.xlsx';
// // 设置下载后的文件名
// link.download = '设计出图计划导入模版.xlsx';
// // 触发点击
// document.body.appendChild(link);
// link.click();
// // 清理
// document.body.removeChild(link);
// } catch (error) {
// alert('下载失败,请重试');
// }
};
// 切换
const handleClick = (val) => {
@ -699,6 +707,7 @@ onUnmounted(() => {
border-collapse: collapse; //合并为一个单一的边框
border-color: rgba(199, 199, 199, 1); //边框颜色按实际自定义即可
}
thead {
tr {
th {
@ -708,16 +717,19 @@ onUnmounted(() => {
letter-spacing: 5px;
padding: 15px;
}
td {
text-align: left;
height: 35px; //设置单元格最小高度
padding: 15px;
}
.th-bg {
background-color: rgba(247, 247, 247, 1);
}
}
}
tbody {
tr {
td {
@ -725,6 +737,7 @@ onUnmounted(() => {
height: 40px; //设置单元格最小高度
padding: 15px;
}
th {
height: 35px; //设置单元格最小高度
text-align: center;
@ -733,6 +746,7 @@ onUnmounted(() => {
}
}
}
.table-content {
box-shadow: 0px 0px 10px #ddd;
padding: 20px;

View File

@ -1,187 +1,102 @@
<template>
<div class="p5" style="width: 100%;height: calc(100vh - 84px);" v-loading="loading">
<div id="TrajectoryEarth" style="width: 100%;height: 100%;"></div>
<div class="p5" style="width: 100%; height: calc(100vh - 84px)" v-loading="loading">
<!-- 返回按钮区域 -->
<div style="position: absolute; top: 20px; left: 20px; z-index: 100; display: flex; gap: 10px">
<el-button type="primary" icon="ArrowLeft" @click="handleBack">返回</el-button>
<el-button type="success" icon="Play" @click="handleStart">开始</el-button>
<el-button type="warning" icon="Pause" @click="handleStop">停止</el-button>
</div>
<div id="TrajectoryEarth" style="width: 100%; height: 100%"></div>
</div>
</template>
<script setup name="equipmentGPS">
import { ref, onMounted, onUnmounted } from 'vue';
import { ElButton } from 'element-plus';
import { ElMessage } from 'element-plus';
import { useRoute, useRouter } from 'vue-router'; // 补充导入useRouter
import { getFootNote } from '@/api/equipment/index';
import { ModelPathMover } from './index.js';
const route = useRoute();
const router = useRouter(); // 初始化router
const loading = ref(true);
let modelMover = null;
// 返回上一页
const handleBack = () => {
router.back();
};
// 开始轨迹运动
const handleStart = () => {
if (modelMover && typeof modelMover.start === 'function') {
try {
modelMover.start();
ElMessage.success('轨迹已开始播放');
} catch (error) {
console.error('启动轨迹失败:', error);
ElMessage.error('启动轨迹失败');
}
} else {
ElMessage.warning('轨迹未初始化,请稍后再试');
}
};
// 停止轨迹运动
const handleStop = () => {
if (modelMover && typeof modelMover.stop === 'function') {
try {
modelMover.stop();
ElMessage.success('轨迹已停止');
} catch (error) {
console.error('停止轨迹失败:', error);
ElMessage.error('停止轨迹失败');
}
} else {
ElMessage.warning('轨迹未初始化,请稍后再试');
}
};
let earthInstance = null;
let data = [
{
"lng": 106.45637808828741,
"lat": 29.5597535878972,
"alt": 0
},
{
"lng": 106.45971817314378,
"lat": 29.54708008996366,
"alt": 0
},
{
"lng": 106.4594902314301,
"lat": 29.53682043192008,
"alt": 0
},
{
"lng": 106.47398277208025,
"lat": 29.5448688679258,
"alt": 0
},
{
"lng": 106.4793889453858,
"lat": 29.549294608101395,
"alt": 0.0016450895529057888
},
{
"lng": 106.49100748408087,
"lat": 29.551808876409023,
"alt": 0
},
{
"lng": 106.5040076285079,
"lat": 29.55321574288158,
"alt": 0
},
{
"lng": 106.51355510567937,
"lat": 29.546776414794298,
"alt": 0
},
{
"lng": 106.51838453732344,
"lat": 29.537721996213506,
"alt": 0
},
{
"lng": 106.51457768703192,
"lat": 29.524855377287736,
"alt": 0.0009144105438296915
},
{
"lng": 106.52872030672225,
"lat": 29.53289655789934,
"alt": 0.0005979679117487334
},
{
"lng": 106.53493249730421,
"lat": 29.541341118458874,
"alt": 0
},
{
"lng": 106.53390022310705,
"lat": 29.54848036964581,
"alt": 0
},
{
"lng": 106.53471751083796,
"lat": 29.55380771856629,
"alt": 0
},
{
"lng": 106.53518023558718,
"lat": 29.560247052020156,
"alt": 0
},
{
"lng": 106.52470634506619,
"lat": 29.560148336926677,
"alt": 0
},
{
"lng": 106.52527983360243,
"lat": 29.55240114606003,
"alt": 0
},
{
"lng": 106.51837614087053,
"lat": 29.557734494325807,
"alt": 0.0021893863172707047
},
{
"lng": 106.51573052195917,
"lat": 29.564878142363643,
"alt": 0
},
{
"lng": 106.50951515081469,
"lat": 29.556427329943944,
"alt": 0
},
{
"lng": 106.5076746620389,
"lat": 29.565884717127823,
"alt": 0
},
{
"lng": 106.50341642164544,
"lat": 29.558842113740727,
"alt": 0
},
{
"lng": 106.50065453145776,
"lat": 29.567897073636868,
"alt": 0
},
{
"lng": 106.49328990493458,
"lat": 29.558741275828908,
"alt": 0
},
{
"lng": 106.49363360765534,
"lat": 29.57333026493932,
"alt": 0
},
{
"lng": 106.51905977395505,
"lat": 29.57828423907017,
"alt": 0
},
{
"lng": 106.51145952743101,
"lat": 29.584527208426245,
"alt": 0
},
{
"lng": 106.49372239119027,
"lat": 29.58774998459616,
"alt": 0
},
{
"lng": 106.48214171543982,
"lat": 29.580866974898736,
"alt": 0.006089177027688381
},
{
"lng": 106.48801515807557,
"lat": 29.57049465877845,
"alt": 0
},
{
"lng": 106.47638485150803,
"lat": 29.571501851940585,
"alt": 0.0011061005102942808
},
{
"lng": 106.47903303165843,
"lat": 29.562542838689904,
"alt": 0.0011137835517156711
},
{
"lng": 106.4645244823306,
"lat": 29.56868284644567,
"alt": 0.00008251706068442191
},
{
"lng": 106.47108853087332,
"lat": 29.555194220499004,
"alt": 0
},
]
'locLongitude': 106.45637808828741,
'locLatitude': 29.5597535878972,
'locAltitude': 0
}
];
// 获取轨迹数据
const getTrajectoryData = async () => {
try {
// 从URL参数中获取clientId、projectId和userId
const { clientId, projectId, userId } = route.query;
if (!clientId || !projectId || !userId) {
ElMessage.warning('缺少必要参数,请检查传入的参数');
return;
}
loading.value = true;
const res = await getFootNote({ clientId, projectId, userId });
if (res && res.code === 200 && res.data && res.data.length > 0) {
data = res.data;
// 渲染轨迹
if (earthInstance && earthInstance.viewer) {
renderRange(data);
}
} else {
ElMessage.warning('暂无轨迹数据');
}
} catch (error) {
console.error('获取轨迹数据失败:', error);
ElMessage.error('获取轨迹数据失败,请稍后重试');
} finally {
loading.value = false;
}
};
// 创建地球
const createEarth = () => {
@ -191,12 +106,12 @@ const createEarth = () => {
}
window.YJ.on({
ws: true,
ws: true
// host: getIP(), // 资源所在服务器地址
// username: this.loginForm.username, // 用户名
// password: md5pass, // 密码
}).then((res) => {
loading.value = false;
})
.then((res) => {
// 创建地球实例
earthInstance = new YJ.YJEarth('TrajectoryEarth');
window.Earth3 = earthInstance;
@ -220,7 +135,7 @@ const createEarth = () => {
};
YJ.Global.CesiumContainer(window.Earth3, {
compass: false, //罗盘
compass: false //罗盘
});
// 加载底图
loadBaseMap(earthInstance.viewer);
@ -228,8 +143,11 @@ const createEarth = () => {
// 可以取消注释以下代码来设置初始视角
// YJ.Global.flyTo(earthInstance, view);
// YJ.Global.setDefaultView(earthInstance.viewer, view)
renderRange(data);
}).catch((err) => {
// 地球创建完成后获取并渲染轨迹数据
getTrajectoryData();
})
.catch((err) => {
console.error('初始化地球失败:', err);
ElMessage.error('初始化地球失败,请稍后重试');
});
@ -274,35 +192,39 @@ const renderRange = (data) => {
}
try {
const positions = data.map((point) => {
return Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.alt || 0);
const positions = data.map((item) => {
return {
lon: item.locLongitude,
lat: item.locLatitude,
height: item.locAltitude || 0,
name: item.name || ''
};
});
const entity = earthInstance.viewer.entities.add({
polyline: {
modelMover = new ModelPathMover(window.Earth3.viewer, {
// modelUrl: './air.glb', // 模型URL
positions: positions,
width: 5,
material: Cesium.Color.RED,
clampToGround: true
}
speed: 50, // 移动速度
loop: true, // 循环运动
iconUrl: '/image/Foot.png', // 模型上方图标
baseHeight: 10 // 外部传入的统一高度(米)
});
// 调整视角以适应轨迹
earthInstance.viewer.flyTo(entity);
window.modelMover = modelMover;
} catch (err) {
console.error('渲染轨迹失败:', err);
ElMessage.error('渲染轨迹失败');
}
};
//
onMounted(() => {
createEarth();
});
//
onUnmounted(() => {
if (modelMover) {
modelMover.stop(); // 组件卸载时停止轨迹
modelMover = null;
}
if (earthInstance) {
earthInstance.destroy();
earthInstance = null;

View File

@ -0,0 +1,392 @@
export class ModelPathMover {
/**
* 构造函数
* @param {Cesium.Viewer} viewer - Cesium viewer实例
* @param {Object} options - 配置选项
* @param {Number} [options.baseHeight=0] - 外部传入的统一高度(米),将叠加到所有位置点上
*/
constructor(viewer, options) {
this.viewer = viewer;
this.modelUrl = options.modelUrl;
this.positions = options.positions || [];
this.speed = options.speed || 10; // 米/秒
this.loop = options.loop !== undefined ? options.loop : true;
this.pathStyle = options.pathStyle || {
color: Cesium.Color.YELLOW,
width: 3
};
this.markerStyle = options.markerStyle || {
color: Cesium.Color.RED,
pixelSize: 10,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2
};
this.iconUrl = options.iconUrl;
this.iconSize = options.iconSize || 32;
this.iconOffset = options.iconOffset || 0;
this.headingOffset = options.headingOffset || 0;
// 新增接收外部传入的统一高度默认0米
this.baseHeight = options.baseHeight || 0;
// 内部状态(保持不变)
this.modelEntity = null;
this.pathEntity = null;
this.markerEntities = [];
this.iconEntity = null;
this.currentIndex = 0;
this.isMoving = false;
this.lastTime = 0;
this.animationFrameId = null;
this.currentPosition = null;
this.progress = 0;
this.modelHeight = 0;
// 初始化
this.init();
// 调试信息增加baseHeight打印
console.log('ModelPathMover初始化完成', {
positionCount: this.positions.length,
speed: this.speed,
loop: this.loop,
baseHeight: this.baseHeight // 打印传入的统一高度
});
}
/**
* 初始化(保持不变)
*/
init() {
if (this.positions.length < 2) {
console.warn('至少需要2个位置点才能进行移动');
}
this.createPath();
this.createMarkers();
this.createModel();
if (this.iconUrl) {
this.createIcon();
}
}
/**
* 创建模型修改叠加baseHeight
*/
createModel() {
if (this.positions.length === 0) return;
const firstPos = this.positions[0];
// 关键修改在原始高度基础上叠加baseHeight
const finalHeight = (firstPos.height || 0) + this.baseHeight;
this.currentPosition = Cesium.Cartesian3.fromDegrees(
firstPos.lon,
firstPos.lat,
finalHeight // 使用叠加后的高度
);
// 初始朝向计算(保持不变)
let initialOrientation = Cesium.Transforms.headingPitchRollQuaternion(this.currentPosition, new Cesium.HeadingPitchRoll(0, 0, 0));
if (this.positions.length > 1) {
const nextPos = this.positions[1];
// 计算下一个点时同样叠加baseHeight
const nextFinalHeight = (nextPos.height || 0) + this.baseHeight;
const nextCartesian = Cesium.Cartesian3.fromDegrees(nextPos.lon, nextPos.lat, nextFinalHeight);
const heading = this.calculateHeading(this.currentPosition, nextCartesian);
initialOrientation = Cesium.Transforms.headingPitchRollQuaternion(this.currentPosition, new Cesium.HeadingPitchRoll(heading, 0, 0));
}
this.modelEntity = this.viewer.entities.add({
name: 'Moving Model',
position: this.currentPosition,
orientation: initialOrientation,
model: {
uri: this.modelUrl,
minimumPixelSize: 64,
readyPromise: (model) => {
const boundingSphere = model.boundingSphere;
if (boundingSphere) {
this.modelHeight = boundingSphere.radius * 2;
console.log('模型高度检测完成:', this.modelHeight, '米');
}
}
}
});
}
/**
* 创建路径修改叠加baseHeight
*/
createPath() {
if (this.positions.length < 2) return;
// 关键修改遍历所有点时给每个点的高度叠加baseHeight
const pathPositions = this.positions.map((pos) => {
const finalHeight = (pos.height || 0) + this.baseHeight;
return Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, finalHeight);
});
this.pathEntity = this.viewer.entities.add({
name: 'Model Path',
polyline: {
positions: pathPositions,
width: this.pathStyle.width,
material: this.pathStyle.color,
clampToGround: false
}
});
}
/**
* 创建位置标记修改叠加baseHeight
*/
createMarkers() {
this.markerEntities = this.positions.map((pos, index) => {
// 关键修改标记点高度同样叠加baseHeight
const finalHeight = (pos.height || 0) + this.baseHeight;
const position = Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, finalHeight);
const marker = this.viewer.entities.add({
name: `Position Marker ${index}`,
position: position,
point: {
color: this.markerStyle.color,
pixelSize: this.markerStyle.pixelSize,
outlineColor: this.markerStyle.outlineColor,
outlineWidth: this.markerStyle.outlineWidth
},
label: {
text: pos.name || `Point ${index + 1}`,
font: '14px sans-serif',
pixelOffset: new Cesium.Cartesian2(0, -20),
fillColor: Cesium.Color.WHITE
}
});
return marker;
});
}
/**
* 创建模型上方的图标(保持不变)
*/
createIcon() {
this.iconEntity = this.viewer.entities.add({
name: 'Model Icon',
position: new Cesium.CallbackProperty(() => {
return this.adjustCartesianHeight(this.currentPosition, 0.3);
}, false),
billboard: {
image: this.iconUrl,
width: this.iconSize,
height: this.iconSize,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM
},
label: {
text: 'Model Icon',
font: '14px sans-serif',
pixelOffset: new Cesium.Cartesian2(0, -40),
fillColor: Cesium.Color.WHITE
}
});
}
/**
* 调整笛卡尔坐标的高度(在原有高度基础上叠加指定值)
* @param {Cesium.Cartesian3} cartesian - 原始笛卡尔坐标
* @param {Number} heightOffset - 要增加的高度值(米,可为负数)
* @param {Cesium.Ellipsoid} [ellipsoid=Cesium.Ellipsoid.WGS84] - 参考椭球体
* @returns {Cesium.Cartesian3|null} 调整高度后的笛卡尔坐标失败返回null
*/
adjustCartesianHeight(cartesian, heightOffset, ellipsoid = Cesium.Ellipsoid.WGS84) {
// 1. 校验输入的笛卡尔坐标是否有效
// if (!Cesium.Cartesian3.isValid(cartesian)) {
// console.error("无效的笛卡尔坐标,无法调整高度");
// return null;
// }
// 2. 笛卡尔坐标 → Cartographic地理坐标含弧度经纬度和高度
const cartographic = Cesium.Cartographic.fromCartesian(cartesian, ellipsoid);
if (!cartographic) {
console.error('笛卡尔坐标转换为Cartographic失败');
return null;
}
// 3. 调整高度在原有高度上叠加offset可为负数
cartographic.height += heightOffset;
// 可选确保高度不低于0根据需求决定是否保留
// cartographic.height = Math.max(cartographic.height, 0);
// 4. Cartographic → 笛卡尔坐标(使用弧度经纬度转换)
const adjustedCartesian = Cesium.Cartesian3.fromRadians(
cartographic.longitude, // 经度(弧度)
cartographic.latitude, // 纬度(弧度)
cartographic.height, // 调整后的高度(米)
ellipsoid
);
return adjustedCartesian;
}
/**
* 开始移动(保持不变)
*/
start() {
if (this.isMoving) {
console.log('模型已经在移动中');
return;
}
if (this.positions.length < 2) {
console.error('无法移动位置点数量不足至少需要2个');
return;
}
this.isMoving = true;
this.lastTime = performance.now();
this.progress = 0;
console.log('开始移动,速度:', this.speed, '米/秒');
this.animate();
}
/**
* 动画循环函数(保持不变)
*/
animate() {
if (!this.isMoving) return;
const currentTime = performance.now();
const timeDeltaMs = currentTime - this.lastTime;
this.lastTime = currentTime;
const timeDelta = timeDeltaMs / 1000;
this.updatePosition(timeDelta);
this.animationFrameId = requestAnimationFrame(() => this.animate());
}
/**
* 停止移动(保持不变)
*/
stop() {
if (!this.isMoving) return;
this.isMoving = false;
console.log('停止移动');
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
/**
* 更新模型位置修改叠加baseHeight
*/
updatePosition(timeDelta) {
if (!this.isMoving) return;
const distanceToMove = this.speed * timeDelta;
const currentPos = this.positions[this.currentIndex];
const nextIndex = (this.currentIndex + 1) % this.positions.length;
const nextPos = this.positions[nextIndex];
// 关键修改计算当前点和下一点时均叠加baseHeight
const currentFinalHeight = (currentPos.height || 0) + this.baseHeight;
const nextFinalHeight = (nextPos.height || 0) + this.baseHeight;
const currentCartesian = Cesium.Cartesian3.fromDegrees(currentPos.lon, currentPos.lat, currentFinalHeight);
const nextCartesian = Cesium.Cartesian3.fromDegrees(nextPos.lon, nextPos.lat, nextFinalHeight);
// 后续逻辑保持不变
const totalDistance = Cesium.Cartesian3.distance(currentCartesian, nextCartesian);
if (totalDistance < 0.001) {
this.currentIndex = nextIndex;
this.progress = 0;
this.setModelPosition(nextCartesian, this.getNextPositionCartesian(nextIndex));
return;
}
this.progress += distanceToMove / totalDistance;
if (this.progress >= 1.0) {
const remainingDistance = (this.progress - 1.0) * totalDistance;
this.currentIndex = nextIndex;
if (!this.loop && this.currentIndex === this.positions.length - 1) {
this.setModelPosition(nextCartesian, null);
this.stop();
console.log('已到达终点,停止移动');
return;
}
const newTotalDistance = Cesium.Cartesian3.distance(nextCartesian, this.getNextPositionCartesian(this.currentIndex));
this.progress = newTotalDistance > 0.001 ? remainingDistance / newTotalDistance : 0;
this.setModelPosition(nextCartesian, this.getNextPositionCartesian(this.currentIndex));
} else {
const newPosition = Cesium.Cartesian3.lerp(currentCartesian, nextCartesian, this.progress, new Cesium.Cartesian3());
this.setModelPosition(newPosition, nextCartesian);
}
this.viewer.scene.requestRender();
}
/**
* 获取下一个位置的笛卡尔坐标修改叠加baseHeight
*/
getNextPositionCartesian(currentIndex) {
const nextIndex = (currentIndex + 1) % this.positions.length;
const nextPos = this.positions[nextIndex];
// 关键修改返回下一点时叠加baseHeight
const finalHeight = (nextPos.height || 0) + this.baseHeight;
return Cesium.Cartesian3.fromDegrees(nextPos.lon, nextPos.lat, finalHeight);
}
/**
* 设置模型位置和方向(保持不变)
*/
setModelPosition(position, targetPosition) {
if (!this.modelEntity) return;
this.currentPosition = position;
this.modelEntity.position.setValue(position);
if (targetPosition) {
const heading = this.calculateHeading(position, targetPosition);
this.modelEntity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, 0, 0)));
}
}
/**
* 计算两点之间的朝向(保持不变)
*/
calculateHeading(from, to) {
const fromCartographic = Cesium.Cartographic.fromCartesian(from);
const toCartographic = Cesium.Cartographic.fromCartesian(to);
const startLat = fromCartographic.latitude;
const startLon = fromCartographic.longitude;
const endLat = toCartographic.latitude;
const endLon = toCartographic.longitude;
const dLon = endLon - startLon;
const y = Math.sin(dLon) * Math.cos(endLat);
const x = Math.cos(startLat) * Math.sin(endLat) - Math.sin(startLat) * Math.cos(endLat) * Math.cos(dLon);
let heading = Math.atan2(y, x);
heading = (heading + Cesium.Math.TWO_PI) % Cesium.Math.TWO_PI;
heading = (heading + this.headingOffset) % Cesium.Math.TWO_PI;
return heading;
}
/**
* 手动设置模型高度(保持不变)
*/
setModelHeight(height) {
this.modelHeight = height;
console.log('手动设置模型高度:', height, '米');
}
/**
* 设置航向角偏移(保持不变)
*/
setHeadingOffset(offsetDegrees) {
this.headingOffset = Cesium.Math.toRadians(offsetDegrees);
console.log('设置航向角偏移:', offsetDegrees, '度');
}
/**
* 销毁所有资源(保持不变)
*/
destroy() {
this.stop();
if (this.modelEntity) this.viewer.entities.remove(this.modelEntity);
if (this.pathEntity) this.viewer.entities.remove(this.pathEntity);
this.markerEntities.forEach((marker) => this.viewer.entities.remove(marker));
if (this.iconEntity) this.viewer.entities.remove(this.iconEntity);
this.modelEntity = null;
this.pathEntity = null;
this.markerEntities = [];
this.iconEntity = null;
}
}

View File

@ -24,27 +24,22 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:equipment:edit']"
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['gps:equipment:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:equipment:remove']"
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['gps:equipment:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.8">
<el-button type="primary" plain icon="User" :disabled="single" @click="handleBindUser()" v-hasPermi="['system:equipment:bindUser']"
<el-button type="primary" plain icon="User" :disabled="single" @click="handleBindUser()" v-hasPermi="['gps:equipment:bindManmachine']"
>绑定用户</el-button
>
</el-col>
<el-col :span="2">
<el-button type="primary" plain @click="handleViewAll" v-hasPermi="['system:equipment:view']">{{ viewAllButtonText }}</el-button>
</el-col>
<!-- 新增跳转空页面按钮 -->
<el-col :span="2">
<el-button type="primary" plain icon="international" @click="handleGoToEmptyPage"> GPS定位 </el-button>
<el-button type="primary" plain @click="handleViewAll">{{ viewAllButtonText }}</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
@ -68,17 +63,7 @@
</el-table-column>
<!-- 设备名称列 -->
<el-table-column label="设备名称" align="center">
<template #default="scope">
<el-button
type="text"
@click="handleOpenHistoryUser(scope.row.clientId, scope.row.userId)"
style="padding: 0; color: #409eff; cursor: pointer"
>
{{ scope.row.deviceName || '-' }}
</el-button>
</template>
</el-table-column>
<el-table-column label="设备名称" align="center" prop="deviceName" />
<el-table-column label="远程连接地址" align="center" prop="remoteAddressStr" />
<el-table-column label="连接创建时间" align="center">
@ -106,7 +91,28 @@
type="primary"
icon="User"
@click="scope.row.type === 1 ? handleUnbindUser(scope.row) : handleBindUser(scope.row)"
v-hasPermi="['gps:equipment:bindUser']"
v-hasPermi="scope.row.type === 1 ? ['gps:equipment:unbindManmachine'] : ['gps:equipment:bindManmachine']"
>
</el-button>
</el-tooltip>
<el-tooltip content="足迹" placement="top">
<el-button
link
type="primary"
icon="Location"
v-hasPermi="['gps:equipmentSon:getList']"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, scope.row.clientId)"
:disabled="!scope.row.userId || !scope.row.projectId"
></el-button>
</el-tooltip>
<el-tooltip content="历史记录" placement="top">
<el-button
link
type="primary"
icon="Clock"
@click="handleOpenHistoryUser(scope.row.clientId, scope.row.userId)"
v-hasPermi="['gps:equipment:getUserList']"
>
</el-button>
</el-tooltip>
@ -141,9 +147,6 @@
<el-option v-for="project in projectList" :key="project.projectId" :label="project.projectName" :value="project.projectId" />
</el-select>
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-input v-model="bindForm.deviceName" disabled placeholder="设备名称" />
</el-form-item>
<el-form-item label="选择用户" prop="userId" required>
<el-select v-model="bindForm.userId" placeholder="请选择用户" clearable>
<el-option v-for="user in userList" :key="user.sysUserId" :label="user.userName" :value="user.sysUserId" />
@ -170,6 +173,7 @@
>
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="项目名称" align="center" prop="projectName" />
<el-table-column label="状态" align="center" width="120">
<template #default="scope">
<el-tag :type="scope.row.type === 0 ? 'success' : 'info'" size="small">
@ -177,6 +181,19 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="80">
<template #default="scope">
<el-tooltip content="足迹" placement="top">
<el-button
link
type="primary"
icon="Location"
v-hasPermi="['gps:equipmentSon:getList']"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, currentHistoryClientId)"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div v-if="!historyUserLoading && historyUserList.length === 0" style="text-align: center; padding: 50px 0">
@ -240,7 +257,7 @@ const projectList = ref<any[]>([]);
const projectLoading = ref(false);
const userLoading = ref(false);
const viewAllButtonText = computed(() => {
return queryParams.value.type === 1 ? '查看未绑定设备' : '查看已绑定设备';
return queryParams.value.type === 1 ? '查看未绑定项目设备' : '查看已绑定项目设备';
});
// 对话框相关
@ -473,9 +490,16 @@ const handleViewAll = () => {
getList();
};
const handleGoToEmptyPage = () => {
const handleGoToEmptyPage = (userId: any, projectId: any, clientId: any) => {
console.log('userId:', userId, 'projectId:', projectId, 'clientId:', clientId);
router.push({
path: './equipmentGPS'
path: './equipmentGPS',
query: {
userId: userId,
projectId: projectId,
clientId: clientId
}
});
};
@ -568,41 +592,53 @@ const handleDelete = async (row?: ExtendedEquipmentVO) => {
};
/** 绑定用户按钮操作 */
const handleBindUser = async (row?: EquipmentVO) => {
const handleBindUser = async (row: ExtendedEquipmentVO) => {
try {
if (!row) {
proxy?.$modal.msgWarning('未获取到设备信息');
return;
}
if (row.id === undefined || row.id === null || row.id === '') {
proxy?.$modal.msgWarning('设备ID不能为空');
return;
}
const deviceId = Number(row.id);
if (isNaN(deviceId) || deviceId <= 0) {
proxy?.$modal.msgWarning(`设备ID格式错误必须是正整数当前值: ${row.id}`);
return;
}
if (!row.clientId || typeof row.clientId !== 'string' || row.clientId.trim() === '') {
proxy?.$modal.msgWarning(`设备标识clientId格式错误必须是非空字符串当前值: ${row.clientId}`);
return;
}
// 初始化表单
Object.assign(bindForm, {
id: undefined,
id: deviceId,
projectId: undefined,
userId: undefined,
clientId: row?.clientId,
deviceName: undefined
clientId: row.clientId,
deviceName: row.deviceName || '未知设备'
});
bindUserFormRef.value?.resetFields();
userList.value = [];
const _id = row?.id || ids.value[0];
try {
const res = await getEquipment(_id);
const equipmentData = res.data;
bindForm.id = equipmentData.id;
bindForm.deviceName = equipmentData.deviceName;
bindForm.clientId = row?.clientId || equipmentData.clientId;
// 加载项目和用户数据
if (projectList.value.length === 0) {
await getProjects();
}
if (equipmentData.projectId) {
bindForm.projectId = equipmentData.projectId;
await getUsersByProjectId(equipmentData.projectId);
} else if (currentProject.value?.id) {
if (currentProject.value?.id) {
bindForm.projectId = currentProject.value.id;
await getUsersByProjectId(currentProject.value.id);
}
bindDialogVisible.value = true;
} catch (error) {
console.error('获取绑定用户信息失败:', error);
proxy?.$modal.msgError('获取数据失败请重试');
console.error('打开绑定用户对话框失败:', error);
proxy?.$modal.msgError('操作失败请重试');
}
};
@ -618,17 +654,9 @@ const submitBindUser = () => {
bindButtonLoading.value = true;
try {
const bindData = {
id: bindForm.id,
projectId: bindForm.projectId,
userId: bindForm.userId,
clientId: bindForm.clientId,
deviceName: bindForm.deviceName
};
console.log('提交绑定用户参数:', bindData);
await bindUser(bindData);
// 直接使用bindForm数据调用bindUser接口
console.log('提交绑定用户参数:', bindForm);
await bindUser(bindForm);
proxy?.$modal.msgSuccess('用户绑定成功');
bindDialogVisible.value = false;
await getList();
@ -708,6 +736,8 @@ const handleOpenHistoryUser = async (clientId: string | number | undefined, curr
historyUserDialogVisible.value = true;
historyUserLoading.value = true;
historyUserList.value = [];
// 保存当前clientId用于足迹操作
currentHistoryClientId.value = clientId;
try {
const res = await gethistroyUser({
@ -732,6 +762,27 @@ const handleOpenHistoryUser = async (clientId: string | number | undefined, curr
}
};
/** 历史弹窗中的足迹操作 */
const handleFootprintOperation = () => {
if (!historyUserList.value || historyUserList.value.length === 0) {
proxy?.$modal.msgWarning('暂无用户数据无法查看足迹');
return;
}
// 获取第一个用户的数据(通常是当前绑定用户)
const firstUser = historyUserList.value[0];
if (!firstUser.sysUserId) {
proxy?.$modal.msgWarning('用户ID不存在无法查看足迹');
return;
}
// 跳转到足迹页面
handleGoToEmptyPage(firstUser.sysUserId, firstUser.projectId || currentProject.value?.id, currentHistoryClientId.value);
};
// 当前历史弹窗的clientId
const currentHistoryClientId = ref('');
/** 页面挂载时初始化 */
onMounted(() => {
getList();

View File

@ -1,6 +1,7 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
@ -11,25 +12,15 @@
<el-input v-model="queryParams.formalitiesId" placeholder="请输入手续办理清单模板id" clearable @keyup.enter="handleQuery" />
</el-form-item> -->
<el-form-item label="计划开始时间" prop="planTheStartTime">
<el-date-picker
clearable
v-model="queryParams.planTheStartTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择计划开始时间"
/>
<el-date-picker clearable v-model="queryParams.planTheStartTime" type="date" value-format="YYYY-MM-DD"
placeholder="请选择计划开始时间" />
</el-form-item>
<el-form-item label="负责人" prop="head">
<el-input v-model="queryParams.head" placeholder="请输入负责人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="实际完成时间" prop="actualCompletionTime">
<el-date-picker
clearable
v-model="queryParams.actualCompletionTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择实际完成时间"
/>
<el-date-picker clearable v-model="queryParams.actualCompletionTime" type="date" value-format="YYYY-MM-DD"
placeholder="请选择实际完成时间" />
</el-form-item>
<!-- <el-form-item label="手续材料" prop="formalitiesUrl">
<el-input v-model="queryParams.formalitiesUrl" placeholder="请输入手续材料" clearable @keyup.enter="handleQuery" />
@ -47,19 +38,21 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['formalities:formalitiesAreConsolidated:getTree']"
>新增</el-button
>
<span style="margin-left: 10px"
><el-tooltip class="box-item" effect="dark" content="从原有模板列表选择新增" placement="top">
<el-icon color="#409efc"><WarningFilled /></el-icon> </el-tooltip
></span>
<el-button type="primary" plain icon="Plus" @click="handleAdd()"
v-hasPermi="['formalities:formalitiesAreConsolidated:getTree']">新增</el-button>
<span style="margin-left: 10px"><el-tooltip class="box-item" effect="dark" content="从原有模板列表选择新增"
placement="top">
<el-icon color="#409efc">
<WarningFilled />
</el-icon> </el-tooltip></span>
</el-col>
<el-col :span="1.5" v-hasPermi="['formalities:listOfFormalities:list']">
<el-button type="primary" plain icon="Plus" @click="addTemplate()">新增数据</el-button>
<span style="margin-left: 10px">
<el-tooltip class="box-item" effect="dark" content="创建新模板并添加数据" placement="top">
<el-icon color="#409efc"><WarningFilled /></el-icon>
<el-icon color="#409efc">
<WarningFilled />
</el-icon>
</el-tooltip>
</span>
</el-col>
@ -78,7 +71,8 @@
</el-row>
</template>
<el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
<el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange"
row-key="id" default-expand-all>
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="手续办理清单模板父级" align="center" prop="formalitiesPname" /> -->
<el-table-column label="手续办理清单" align="left" prop="formalitiesName" />
@ -101,51 +95,52 @@
<el-table-column label="办理状态" align="center" prop="processingStatus" />
<el-table-column label="手续材料" align="center" prop="formalitiesUrl" width="180">
<template #default="scope">
<el-link type="primary" :underline="false" @click="handlePreview(scope.row)" target="_blank" v-if="scope.row.formalitiesPid"
>查看</el-link
>
<div style="display: flex; justify-content: center; align-items: center;">
<div>
<el-link type="primary" :underline="false" @click="handlePreview(scope.row)" target="_blank"
v-if="scope.row.formalitiesPid">查看</el-link>
</div>
<div>
<el-badge v-if="scope.row.fileCount" :value="scope.row.fileCount" class="item" type="danger">
</el-badge>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<div v-if="scope.row.formalitiesPid">
<el-button
link
type="primary"
icon="Edit"
v-if="scope.row.processingStatus != '已完成'"
<el-button link type="primary" icon="Edit" v-if="scope.row.processingStatus != '已完成'"
@click="handleUpdate(scope.row)"
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']"
>修改</el-button
>
<el-button link type="primary" icon="Upload" v-if="scope.row.processingStatus != '已完成'" @click="handleUpload(scope.row)"
>上传</el-button
>
<el-button
link
type="primary"
icon="EditPen"
@click="handleUpdateStatus(scope.row)"
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']"
>修改状态</el-button
>
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']">修改</el-button>
<el-button link type="primary" icon="Upload" v-if="scope.row.processingStatus != '已完成'"
@click="handleUpload(scope.row)">上传</el-button>
<el-button link type="primary" icon="EditPen" @click="handleUpdateStatus(scope.row)"
v-hasPermi="['formalities:formalitiesAreConsolidated:edit']">修改状态</el-button>
</div>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改合规性手续合账对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="formalitiesAreConsolidatedFormRef" :model="form" :rules="rules" label-width="160px">
<el-form-item label="计划开始时间" prop="planTheStartTime">
<el-date-picker clearable v-model="form.planTheStartTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择计划开始时间">
<el-date-picker clearable v-model="form.planTheStartTime" type="date" value-format="YYYY-MM-DD"
placeholder="请选择计划开始时间">
</el-date-picker>
</el-form-item>
<el-form-item label="计划完成时间" prop="planTheStartTime">
<el-date-picker clearable v-model="form.planTheEndTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择计划完成时间">
<el-date-picker clearable v-model="form.planTheEndTime" type="date" value-format="YYYY-MM-DD"
placeholder="请选择计划完成时间">
</el-date-picker>
</el-form-item>
<el-form-item label="负责人" prop="head">
@ -167,24 +162,20 @@
<el-table :data="fileList" style="width: 100%" border v-loading="fileLoading">
<el-table-column prop="fileName" label="文件" align="center">
<template #default="scope">
<el-link :key="scope.row.annexUrl" :href="scope.row.annexUrl" target="_blank" type="primary" :underline="false">
<el-link :key="scope.row.annexUrl" :href="scope.row.annexUrl" target="_blank" type="primary"
:underline="false">
{{ scope.row.fileName || '查看文件' }}
</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center" v-if="fileStatus != '1'">
<el-table-column label="操作" align="center" v-if="fileStatus != '1'">
<template #default="scope">
<el-button type="danger" link icon="Delete" @click="handleDeleteFile(scope.row)"> 删除 </el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="fileTotal > 0"
:total="fileTotal"
v-model:page="fileParams.pageNum"
v-model:limit="fileParams.pageSize"
@pagination="getFileList"
/>
<pagination v-show="fileTotal > 0" :total="fileTotal" v-model:page="fileParams.pageNum"
v-model:limit="fileParams.pageSize" @pagination="getFileList" />
<template #footer>
<span>
<el-button type="primary" @click="viewVisible = false">关闭</el-button>
@ -194,18 +185,9 @@
<!-- 上传文件对话框 -->
<el-dialog draggable title="上传文件" v-model="fileVisible" width="450">
<el-form-item label="上传文件" prop="processingStatus">
<file-upload
v-model="file"
ref="uploadRef"
uploadUrl="/formalities/formalitiesAnnex"
v-hasPermi="['formalities:formalitiesAnnex:add']"
:data="{ formalitiesId: form.id }"
:fileType="['pdf']"
:auto-upload="false"
showFileList
method="put"
:onUploadSuccess="handleUploadSuccess"
/>
<file-upload v-model="file" ref="uploadRef" uploadUrl="/formalities/formalitiesAnnex"
v-hasPermi="['formalities:formalitiesAnnex:add']" :data="{ formalitiesId: form.id }" :fileType="['pdf']"
:auto-upload="false" showFileList method="put" :onUploadSuccess="handleUploadSuccess" />
</el-form-item>
<template #footer>
<span>
@ -233,21 +215,19 @@
</el-dialog>
<el-dialog title="新增合规性手续合账" v-model="templateVisbile" width="450">
<el-form-item label="合规性手续模板">
<el-cascader
v-model="tempValue"
:options="tempTreeList"
:props="{
<el-cascader v-model="tempValue" :options="tempTreeList" :props="{
multiple: true,
value: 'id',
label: 'name',
disabled: (node: any) => {
return (node.pid == 0 && !node.children.length) || node.status == 1; // 有 parent 的是二级,没有 parent 的是一级,禁用一级
}
}"
/>
}" />
<div style="margin-left: 10px; display: flex; justify-content: center; align-items: center">
<el-tooltip class="box-item" effect="dark" content="列表上已选择得模版不可再选" placement="top">
<el-icon><WarningFilled /></el-icon>
<el-icon>
<WarningFilled />
</el-icon>
</el-tooltip>
</div>
</el-form-item>
@ -268,7 +248,8 @@
<el-option v-for="item in listOfFormalitiesList" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="名称" prop="formalitiesName" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
<el-form-item label="名称" prop="formalitiesName"
:rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
<el-input v-model="formTemplate.formalitiesName" placeholder="请输入名称" />
</el-form-item>
</el-form>

View File

@ -31,13 +31,20 @@
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="listOfFormalitiesList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
<el-table
v-loading="loading"
:data="listOfFormalitiesList"
@selection-change="handleSelectionChange"
row-key="id"
default-expand-all
style="height: calc(100vh - 300px); overflow-y: auto"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="名称" prop="name" />
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改手续办理清单模板对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="listOfFormalitiesFormRef" :model="form" :rules="rules" label-width="80px">

View File

@ -0,0 +1,90 @@
<template>
<div class="p-2">
<el-table size="small" v-if="props.row.length !== 0" :data="props.row">
<el-table-column label="材料名称" align="center" prop="materialsName" />
<!-- <el-table-column label="材料数量" align="center" prop="quantityCount" /> -->
<el-table-column label="剩余量" align="center" prop="residue">
<template #default="scope">
<span>{{ scope.row.residue }}</span>
</template>
</el-table-column>
<el-table-column label="出库数量" align="center" prop="number">
<template #default="scope">
<el-input-number v-if="scope.row.type" v-model="scope.row.number" :controls="false" :min="0" :max="scope.row.residue" :precision="0" />
<span v-else>{{ scope.row.number }}</span>
</template>
</el-table-column>
<el-table-column label="交接单位" align="center" prop="recipient">
<template #default="scope">
<el-input v-if="scope.row.type" style="width: 150px" v-model="scope.row.recipient" />
<span v-else>{{ scope.row.recipient }}</span>
</template>
</el-table-column>
<el-table-column label="领用人" align="center" prop=" shipper">
<template #default="scope">
<el-input v-if="scope.row.type" style="width: 150px" v-model="scope.row.shipper" />
<span v-else>{{ scope.row.shipper }}</span>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" prop="operator">
<template #default="scope">
<el-input v-if="scope.row.type" style="width: 150px" v-model="scope.row.operator" />
<span v-else>{{ scope.row.operator }}</span>
</template>
</el-table-column>
<el-table-column label="出库时间" align="center" prop="outPutTime" width="180" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" @click="handleConfirm(scope.row)" v-if="scope.row.type"> 确认 </el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { useUserStoreHook } from '@/store/modules/user';
import { addOutbound } from '@/api/materials/materialOutbound';
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const emit = defineEmits(['success']);
const props = defineProps({
row: {
type: Array,
default: () => []
}
});
const handleConfirm = async (row: any) => {
if (row.number == 0 || !row.number) {
ElMessage.error('请输入出库数量');
return;
}
if (!row.shipper) {
ElMessage.error('请输入领用人');
return;
}
if (!row.operator) {
ElMessage.error('请输入操作人');
return;
}
console.log(row);
const params = {
...row,
materialsId: row.id,
projectId: currentProject.value?.id,
outPut: '1'
};
console.log(params);
const data = await addOutbound(params);
if (data.code === 200) {
ElMessage.success('出库成功');
emit('success');
}
};
</script>

View File

@ -0,0 +1,148 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="材料名称" prop="materialName">
<el-input v-model="queryParams.materialName" placeholder="请输入材料名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<el-table
v-loading="loading"
:data="tableList"
:row-key="
(row) => {
return row.id;
}
"
@row-click="
(row, column, event) => {
// 阻止点击行时自动展开
if (column.property) event.stopPropagation();
}
"
:preserve-expanded-content="true"
>
<el-table-column type="expand">
<template #default="{ row }">
<outbound :row="row.children ?? []" @success="getTableList" />
</template>
</el-table-column>
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="材料名称" align="center" prop="materialsName" />
<el-table-column label="规格" align="center" prop="typeSpecificationName" />
<el-table-column label="计量单位" align="center" prop="weightId" />
<el-table-column label="材料数量" align="center" prop="quantityCount" />
<el-table-column label="剩余量" align="center" prop="residue" />
<el-table-column label="操作人" align="center" prop="operator"> </el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Plus" @click="handleoutbound(scope.row)"> 新增出库 </el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getTableList"
/>
</el-card>
</div>
</template>
<script setup lang="ts">
import { outboundMaterials } from '@/api/materials/materialOutbound';
import { useUserStoreHook } from '@/store/modules/user';
import outbound from './component/outbound.vue';
import { number } from 'vue-types';
const { proxy } = getCurrentInstance() as any;
const queryFormRef = ref();
const queryParams = ref({
materialName: '',
pageNum: 1,
pageSize: 10
});
const total = ref(0);
const loading = ref(false);
const tableList = ref([]);
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
//获取列表数据
const getTableList = async () => {
try {
loading.value = true;
const res = await outboundMaterials({ ...queryParams.value, projectId: currentProject.value?.id });
if (res.code === 200) {
loading.value = false;
tableList.value = res.rows;
total.value = res.data.total;
}
} catch (error) {
loading.value = false;
}
};
getTableList();
// 出入库
const handleoutbound = (row: any) => {
console.log(row);
if (row.children == null) {
row.children = [];
}
if (row.children.some((child) => child.type === 'add')) {
ElMessage.warning('已经存在出库记录,不能重复添加');
return;
}
row.children.push({
type: 'add',
id: row.id,
number: 0,
operator: '',
shipper: '',
recipient: '',
residue: row.residue,
materialsName: row.materialsName
});
// 手动触发展开行
const table = document.querySelector('.el-table__body-wrapper');
const rows = table?.querySelectorAll('.el-table__row');
const rowEl = rows?.[Array.from(tableList.value).indexOf(row)];
const expandBtn: any = rowEl?.querySelector('.el-table__expand-icon');
// 如果行未展开,则点击展开按钮
if (expandBtn && !expandBtn.classList.contains('el-table__expand-icon--expanded')) {
expandBtn.click();
}
};
//搜索
const handleQuery = () => {
queryParams.value.pageNum = 1;
getTableList();
};
//重置
const resetQuery = () => {
console.log(111111111);
queryFormRef.value?.resetFields();
handleQuery();
};
</script>
<style scoped></style>

View File

@ -1,22 +1,20 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<div class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="材料名称" prop="materialsName">
<el-input v-model="queryParams.materialsName" placeholder="请输入材料名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" v-hasPermi="['materials:materialsInventory:list']" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" v-hasPermi="['materials:materialsInventory:list']" @click="resetQuery">重置</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
@ -25,275 +23,179 @@
导出
</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getTableList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="materialsInventoryList" @expand-change="handleExpandChange">
<el-table-column type="expand">
<template #default="props">
<div style="margin-left: 60px">
<el-table :data="materialsUseRecordList" border v-loading="loadingChild">
<el-table-column label="序号" align="center" type="index" width="60" />
<el-table-column label="使用数量" align="center" prop="useNumber" />
<el-table-column label="剩余量" align="center" prop="residueNumber" />
<el-table-column label="使用部位" align="center" prop="usePart" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table :data="tableData" row-key="id" border default-expand-all class="custom-table">
<el-table-column prop="materialsName" label="物资名称" align="left" class-name="inventory-register" />
<el-table-column prop="quantityCount" label="计划数量" align="center" class-name="inventory-register" />
<el-table-column label="入库登记" align="center" class-name="inventory-register">
<el-table-column prop="supplier" label="供货单位" align="center" class-name="inventory-register" />
<el-table-column prop="number" label="数量" align="center" class-name="inventory-register" />
<el-table-column prop="operator" label="签收人" align="center" class-name="inventory-register" />
<el-table-column prop="enterTime" label="日期" align="center" class-name="inventory-register" />
</el-table-column>
<el-table-column label="出库登记" align="center" class-name="out-register">
<el-table-column prop="recipient" label="接受单位" align="center" class-name="out-register" />
<el-table-column prop="outNumber" label="数量" align="center" class-name="out-register" />
<el-table-column prop="outOperator" label="出库人" align="center" class-name="out-register" />
<el-table-column prop="shipper" label="领用人" align="center" class-name="out-register" />
<el-table-column prop="createTime" label="领用日期" align="center" class-name="out-register" />
</el-table-column>
<el-table-column label="到货剩余登记" align="center" class-name="out-register">
<el-table-column prop="residue" label="剩余量" align="center" class-name="out-register" />
<el-table-column prop="disposition" label="处理方式" align="center" class-name="out-register" />
</el-table-column>
<el-table-column label="使用登记" align="center" class-name="use-register">
<el-table-column prop="usePart" label="使用部位" align="center" class-name="use-register" />
<el-table-column prop="useNumber" label="使用数量" align="center" class-name="use-register" />
<el-table-column prop="useTime" label="使用日期" align="center" class-name="use-register" />
<el-table-column prop="residueNumber" label="剩余量" align="center" class-name="use-register" />
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" class-name="use-register" />
</el-table>
<pagination
v-show="totalChild > 0"
:total="totalChild"
v-model:page="queryParamsChild.pageNum"
v-model:limit="queryParamsChild.pageSize"
@pagination="getListChild"
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getTableList"
/>
</div>
</template>
</el-table-column>
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="物资名称" align="center" prop="materialsName" />
<el-table-column label="计划数量" align="center" prop="quantityCount" />
<el-table-column label="入库登记" align="center">
<el-table-column label="数量" align="center" prop="number">
<template #default="scope">
<span v-if="scope.row.outPut === '0'">{{ scope.row.number }}</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="签收人" align="center" prop="operator">
<template #default="scope">
<span v-if="scope.row.outPut === '0'">{{ scope.row.operator }}</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="日期" align="center" prop="outPutTime" width="160">
<template #default="scope">
<span v-if="scope.row.outPut === '0'">{{ parseTime(scope.row.outPutTime, '{y}{m}{d}') }}</span>
<span v-else></span>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="出库登记" align="center">
<el-table-column label="交接单位" align="center" prop="recipient" />
<el-table-column label="使用部位" align="center" prop="usePart" />
<el-table-column label="数量" align="center" prop="number">
<template #default="scope">
<span v-if="scope.row.outPut === '1'">{{ scope.row.number }}</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="出库人" align="center" prop="operator">
<template #default="scope">
<span v-if="scope.row.outPut === '1'">{{ scope.row.operator }}</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="领用人" align="center" prop="shipper" />
<el-table-column label="日期" align="center" prop="outPutTime" width="160">
<template #default="scope">
<span v-if="scope.row.outPut === '1'">{{ parseTime(scope.row.outPutTime, '{y}{m}{d}') }}</span>
<span v-else></span>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="剩余处理" align="center">
<el-table-column label="剩余量" align="center" prop="residue" />
<el-table-column label="处理方式" align="center" prop="disposition" />
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-space wrap>
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialsInventory:edit']">
修改
</el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialsInventory:remove']">
删除
</el-button>
</el-space>
</template>
</el-table-column> -->
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改材料出/入库对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="materialsInventoryFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="出入库状态" prop="outPut">
<el-select v-model="form.outPut" clearable placeholder="请输入出入库状态">
<el-option v-for="item in out_put_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="出/入库的数量" prop="number">
<el-input v-model="form.number" placeholder="请输入出/入库的数量" />
</el-form-item>
<el-form-item label="出/入库操作时间" prop="outPutTime">
<el-date-picker clearable v-model="form.outPutTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择出/入库操作时间">
</el-date-picker>
</el-form-item>
<el-form-item label="剩余库存数量" prop="residue">
<el-input v-model="form.residue" placeholder="请输入剩余库存数量" />
</el-form-item>
<el-form-item label="操作人" prop="operator">
<el-input v-model="form.operator" placeholder="请输入操作人" />
</el-form-item>
<el-form-item label="材料出入证明" prop="path">
<el-input v-model="form.path" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="处理方式" prop="disposition">
<el-input v-model="form.disposition" placeholder="请输入处理方式" />
</el-form-item>
<el-form-item label="交接单位" prop="recipient">
<el-input v-model="form.recipient" placeholder="请输入交接单位" />
</el-form-item>
<el-form-item label="领用人" prop="shipper">
<el-input v-model="form.shipper" placeholder="请输入领用人" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="MaterialsInventory" lang="ts">
import {
addMaterialsInventory,
delMaterialsInventory,
getMaterialsInventory,
listMaterialsInventory,
updateMaterialsInventory
} from '@/api/materials/materialsInventory';
import { MaterialsInventoryForm, MaterialsInventoryQuery, MaterialsInventoryVO } from '@/api/materials/materialsInventory/types';
import { useUserStoreHook } from '@/store/modules/user';
import { listMaterialsUseRecord } from '@/api/materials/materialsUseRecord';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { out_put_type } = toRefs<any>(proxy?.useDict('out_put_type'));
<script setup lang="ts">
import useUserStore from '@/store/modules/user';
import { getLedgerList } from '@/api/materials/materialsInventory';
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const { proxy } = getCurrentInstance() as any;
const userStore = useUserStore();
const currentProject = computed(() => userStore.selectedProject);
const materialsInventoryList = ref<MaterialsInventoryVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const queryFormRef = ref();
const queryParams = ref({
materialsName: '',
pageNum: 1,
pageSize: 10
});
const total = ref(0);
const loadingChild = ref(true);
const totalChild = ref(0);
const materialsUseRecordList = ref<any[]>([]);
const queryFormRef = ref<ElFormInstance>();
const materialsInventoryFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: MaterialsInventoryForm = {
id: undefined,
materialsId: undefined,
projectId: currentProject.value?.id,
outPut: undefined,
number: undefined,
outPutTime: undefined,
residue: undefined,
operator: undefined,
path: undefined,
disposition: undefined,
recipient: undefined,
shipper: undefined,
remark: undefined
const tableRef = ref();
const showSearch = ref(true);
const loading = ref(false);
const tableData = ref([]);
//获取列表
const getTableList = async () => {
const parmas = {
...queryParams.value,
projectId: currentProject.value.id
};
const data = reactive({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
materialsId: undefined,
projectId: currentProject.value?.id,
outPut: undefined,
number: undefined,
outPutTime: undefined,
residue: undefined,
operator: undefined,
path: undefined,
disposition: undefined,
recipient: undefined,
shipper: undefined,
params: {}
},
queryParamsChild: {
pageNum: 1,
pageSize: 10,
inventoryId: undefined,
usePart: undefined,
useNumber: undefined,
residueNumber: undefined
},
rules: {
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }],
materialsId: [{ required: true, message: '材料id不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules, queryParamsChild } = toRefs(data);
const materialsOptions = ref([]);
/** 处理外层表格展开/折叠记录当前展开行的inventoryId */
const handleExpandChange = (row: any) => {
queryParamsChild.value.inventoryId = row.id;
getListChild();
};
/** 查询材料子级登记列表(内层列表) */
const getListChild = async () => {
loadingChild.value = true;
try {
const res = await listMaterialsUseRecord(queryParamsChild.value);
materialsUseRecordList.value = res.rows;
totalChild.value = res.total;
} finally {
loadingChild.value = false;
}
};
/** 查询材料出/入库列表 */
const getList = async () => {
loading.value = true;
const res = await listMaterialsInventory(queryParams.value);
materialsInventoryList.value = res.rows;
const res = await getLedgerList(parmas);
if (res.code === 200) {
const data = restructureData(res.rows);
tableData.value = data;
total.value = res.total;
const materialsMap = new Map();
materialsOptions.value = Array.from(materialsMap.values());
loading.value = false;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
// 重组数据结构的函数
const restructureData = (data) => {
return data.map((item) => {
const newItem: any = {
id: item.id,
materialsName: item.materialsName,
quantityCount: item.quantityCount,
supplier: item.supplier,
number: item.number,
operator: item.operator,
enterTime: item.enterTime,
children: []
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
materialsInventoryFormRef.value?.resetFields();
if (item.outList && item.outList.length > 0) {
// 处理第一个outList项目
const firstOut = item.outList[0];
newItem.recipient = firstOut.recipient;
newItem.outNumber = firstOut.number;
newItem.outOperator = firstOut.operator;
newItem.shipper = firstOut.shipper;
newItem.createTime = firstOut.createTime;
newItem.residue = firstOut.residue;
newItem.disposition = firstOut.disposition;
// 处理第一个outList中的useList
if (firstOut.useList && firstOut.useList.length > 0) {
const firstUse = firstOut.useList[0];
newItem.usePart = firstUse.usePart;
newItem.useNumber = firstUse.useNumber;
newItem.useTime = firstUse.createTime;
newItem.residueNumber = firstUse.residueNumber;
newItem.remark = firstUse.remark;
// 将剩余的useList项目添加到children
for (let i = 1; i < firstOut.useList.length; i++) {
const useItem = firstOut.useList[i];
newItem.children.push({
id: useItem.id,
usePart: useItem.usePart,
useNumber: useItem.useNumber,
useTime: useItem.createTime,
residueNumber: useItem.residueNumber,
remark: useItem.remark,
type: 'use'
});
}
}
// 处理剩余的outList项目
for (let i = 1; i < item.outList.length; i++) {
const outItem = item.outList[i];
const outNode: any = {
id: outItem.id,
recipient: outItem.recipient,
outNumber: outItem.number,
outOperator: outItem.operator,
shipper: outItem.shipper,
createTime: outItem.createTime,
residue: outItem.residue,
disposition: outItem.disposition,
type: 'out',
children: []
};
// 处理当前outList项目中的useList
if (outItem.useList && outItem.useList.length > 0) {
const firstUse = outItem.useList[0];
outNode.usePart = firstUse.usePart;
outNode.useNumber = firstUse.useNumber;
outNode.useTime = firstUse.createTime;
outNode.residueNumber = firstUse.residueNumber;
outNode.remark = firstUse.remark;
// 将剩余的useList项目添加到children
for (let j = 1; j < outItem.useList.length; j++) {
const useItem = outItem.useList[j];
outNode.children.push({
id: useItem.id,
usePart: useItem.usePart,
useNumber: useItem.useNumber,
useTime: useItem.createTime,
residueNumber: useItem.residueNumber,
remark: useItem.remark,
type: 'use'
});
}
}
newItem.children.push(outNode);
}
}
return newItem;
});
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
getTableList();
};
/** 重置按钮操作 */
@ -302,75 +204,46 @@ const resetQuery = () => {
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: MaterialsInventoryVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 修改按钮操作 */
const handleUpdate = async (row?: MaterialsInventoryVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getMaterialsInventory(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改材料出/入库';
};
/** 提交按钮 */
const submitForm = () => {
materialsInventoryFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.projectId = currentProject.value?.id;
if (form.value.id) {
await updateMaterialsInventory(form.value).finally(() => (buttonLoading.value = false));
} else {
await addMaterialsInventory(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: MaterialsInventoryVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除材料出/入库编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delMaterialsInventory(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
//导出
const handleExport = () => {
proxy?.download(
'materials/materialsInventory/export',
'/materials/materials/export',
{
...queryParams.value
projectId: currentProject.value?.id
},
`materialsInventory_${new Date().getTime()}.xlsx`
`物资跟踪管理台账.xlsx`
);
};
//监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,
(nid, oid) => {
queryParams.value.projectId = nid;
form.value.projectId = nid;
getList();
}
);
onUnmounted(() => {
listeningProject();
});
onMounted(() => {
getList();
getTableList();
});
</script>
<style lang="scss">
/* 关键样式 - 确保选择器有足够优先级 */
.custom-table .el-table__body .inventory-register,
.custom-table .el-table__header .inventory-register {
background-color: #f0f9ff !important;
}
.custom-table .el-table__body .out-register,
.custom-table .el-table__header .out-register {
background-color: #f0fff3 !important;
}
.custom-table .el-table__body .use-register,
.custom-table .el-table__header .use-register {
background-color: #fffaf0 !important;
}
/* 表头样式增强 */
.el-table__header th {
background-color: #eef1f6;
font-weight: bold;
}
/* 操作按钮样式 */
.operation-buttons {
margin-bottom: 15px;
}
</style>

View File

@ -1,5 +1,13 @@
<template>
<div class="p-2">
<el-row :gutter="10" class="mb8">
<el-col :span="5">
<el-card shadow="never">
<el-tree style="max-width: 600px" :data="TreeData" :props="defaultProps" @node-click="handleNodeClick" />
</el-card>
</el-col>
<el-col :span="19">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> </transition>
<el-card shadow="never">
<template #header>
@ -77,8 +85,17 @@
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
</el-col>
</el-row>
<!-- 添加或修改材料使用登记对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="materialsUseRecordFormRef" :model="form" :rules="rules" label-width="80px">
@ -115,7 +132,7 @@ import { MaterialsUseRecordVO, MaterialsUseRecordQuery, MaterialsUseRecordForm }
import { getCurrentInstance, ComponentInternalInstance, onMounted, ref, reactive, toRefs, computed, watch, WatchStopHandle } from 'vue';
import { ElFormInstance, ElTable } from 'element-plus';
import useUserStore from '@/store/modules/user';
import { get } from 'lodash';
import { getMaterialsList } from '@/api/materials/materialOutbound';
// 类型定义补充
interface DialogOption {
@ -183,7 +200,8 @@ const data = reactive({
projectId: currentProject.value?.id,
outPut: 1,
materialsName: undefined,
usePart: undefined
usePart: undefined,
materialsId: ''
} as MaterialsUseRecordQuery & {
outPut?: number;
materialsName?: string;
@ -199,6 +217,32 @@ const data = reactive({
const { form, rules } = toRefs(data);
const queryParams = ref<typeof data.queryParams>({ ...data.queryParams });
const TreeData: any = ref([]);
//获取材料列表
const getMaterialsListData = async () => {
const res = await getMaterialsList({ projectId: currentProject.value?.id, pageNum: 1, pageSize: 999 });
if (res.code === 200) {
// 将数据转换为树形结构
TreeData.value = res.rows.map((item) => ({
...item,
label: item.materialsName + '_' + item.createTime,
children: []
}));
queryParams.value.materialsId = TreeData.value[0].id;
getList();
}
};
const handleNodeClick = (data: any) => {
console.log(data);
queryParams.value.materialsId = data.id;
getList();
};
const defaultProps = {
children: 'children',
label: 'label'
};
// ------------------------------ 子列表状态工具函数 ------------------------------
/** 获取或初始化指定父行的子列表状态 */
@ -420,6 +464,7 @@ onUnmounted(() => {
// 页面挂载时加载数据
onMounted(() => {
getList();
// getList();
getMaterialsListData();
});
</script>

File diff suppressed because it is too large Load Diff

View File

@ -133,7 +133,7 @@
></el-col>
<el-col :span="12" :offset="0"
><el-form-item label="供应商" prop="supplier">
<el-select v-model="form.supplierId" value-key="id" placeholder="请选择供应商" clearable filterable @change="">
<el-select v-model="form.supplierId" value-key="id" placeholder="请选择供应商" clearable filterable @change="getPlanList">
<el-option v-for="item in supplierOptions" :key="item.id" :label="item.supplierName" :value="item.id"> </el-option>
</el-select> </el-form-item
></el-col>
@ -145,7 +145,14 @@
></el-col>
<el-col :span="12" :offset="0">
<el-form-item label="需求计划" prop="planId">
<el-select v-model="form.planId" value-key="id" placeholder="请选择需求计划" multiple filterable :disabled="!form.mrpBaseId">
<el-select
v-model="form.planId"
value-key="id"
placeholder="请选择需求计划"
multiple
filterable
:disabled="!form.mrpBaseId && !form.supplierId"
>
<el-option v-for="item in planList" :key="item.id" :label="item.name" :value="item.id"> </el-option>
</el-select> </el-form-item
></el-col>
@ -190,18 +197,17 @@
></el-col> -->
</el-row>
</el-form>
<el-table v-loading="loading" :data="selectPlanList" v-if="form.id">
<el-table v-loading="loading" :data="selectPlanList">
<el-table-column label="物资名称" align="center" prop="name" />
<el-table-column label="质量标准" align="center" prop="qs" />
<el-table-column label="规格型号" align="center" prop="specification" />
<el-table-column label="计量单位" align="center" prop="unit" width="80" />
<el-table-column label="需求数量" align="center" prop="demandQuantity" v-if="form.docType == 2">
<el-table-column label="需求数量" align="center" prop="demandQuantity">
<template #default="scope">
<el-input v-model="scope.row.demandQuantity" placeholder="请输入" type="number" />
</template>
</el-table-column>
<el-table-column label="需求数量" align="center" prop="demandQuantity" v-else />
<!-- <el-table-column label="需求数量" align="center" prop="demandQuantity" v-else /> -->
<!-- <el-table-column label="需求到货时间" align="center" prop="arrivalTime" width="250" /> -->
<el-table-column label="备注" align="center" prop="remark" />
</el-table>
@ -357,6 +363,7 @@ const data = reactive({
docCode: [{ required: true, message: '采购单编号不能为空', trigger: 'blur' }],
planId: [{ required: true, message: '需求计划不能为空', trigger: 'blur' }],
mrpBaseId: [{ required: true, message: '需求批次号不能为空', trigger: 'blur' }],
supplierId: [{ required: true, message: '供应商不能为空', trigger: 'blur' }],
// 电话号码验证
technicalDirectorTel: [
{ required: true, message: '请输入电话', trigger: 'blur' },
@ -461,9 +468,16 @@ const handleUpdate = async (row?: PurchaseDocVO) => {
const _id = row?.id || ids.value[0];
const res = await getPurchaseDoc(_id);
Object.assign(form.value, res.data);
getPlanList();
form.value.planId = form.value.associationList?.map((item: any) => item.planId);
await getPlanList();
form.value.planId = form.value.associationList?.map((item: any) => item.planId);
planList.value.forEach((item) => {
form.value.associationList.forEach((items: any) => {
if (item.id == items.planId) {
item.demandQuantity = items.demandQuantity;
}
});
});
dialog.visible = true;
dialog.title = '修改物资-采购联系单';
};
@ -471,6 +485,7 @@ const handleUpdate = async (row?: PurchaseDocVO) => {
const selectPlanList = computed(() => {
if (!form.value.planId) return [];
const result = planList.value.filter((item) => form.value.planId.includes(item.id));
return result;
});
@ -479,11 +494,12 @@ const submitForm = () => {
purchaseDocFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
form.value.associationList = form.value.planId?.map((item: any) => ({
planId: item
}));
form.value.associationList = selectPlanList.value;
form.value.associationList.forEach((item: any) => {
item.planId = item.id;
delete item.id;
});
form.value.supplier = supplierOptions.value.find((item) => item.id == form.value.supplierId)?.supplierName;
if (form.value.id) {
await updatePurchaseDoc(form.value).finally(() => (buttonLoading.value = false));
} else {
@ -498,13 +514,16 @@ const submitForm = () => {
const getPlanList = async () => {
form.value.planId = '';
if (form.value.mrpBaseId && form.value.supplierId) {
const res = await getBatch({
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
mrpBaseId: form.value.mrpBaseId
mrpBaseId: form.value.mrpBaseId,
supplierId: form.value.supplierId
});
planList.value = res.rows;
}
};
const getBatchList = async () => {

View File

@ -14,6 +14,7 @@
</el-form-item>
<el-form-item label="类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择类型">
<el-option label="全部" value="0" />
<el-option label="对甲" value="1" />
<el-option label="对乙" value="2" />
</el-select>
@ -102,7 +103,7 @@
<script setup name="MonthPlan" lang="ts">
import { listMonthPlan, getMonthPlan, delMonthPlan, addMonthPlan, updateMonthPlan } from '@/api/out/monthPlan';
import { MonthPlanVO, MonthPlanQuery, MonthPlanForm } from '@/api/out/monthPlan/types';
import { MonthPlanVO } from '@/api/out/monthPlan/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { out_value_type } = toRefs<any>(proxy?.useDict('out_value_type'));
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
@ -112,13 +113,7 @@ import { useUserStoreHook } from '@/store/modules/user';
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const month = computed(() => {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // getMonth() 从0开始
const currentMonth = `${year}-${month}`;
return currentMonth;
});
const month = '';
const monthPlanList = ref<MonthPlanVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
@ -163,7 +158,7 @@ const data = reactive({
valueType: undefined,
planAuditStatus: undefined,
completeAuditStatus: undefined,
type: '1',
type: '0',
params: {}
},
rules: {
@ -180,7 +175,11 @@ const { queryParams, form, rules } = toRefs(data);
/** 查询月度产值计划列表 */
const getList = async () => {
loading.value = true;
const res = await listMonthPlan(queryParams.value);
let type = queryParams.value.type;
if (type == '0') {
type = '';
}
const res = await listMonthPlan({ ...queryParams.value, type: type });
monthPlanList.value = res.rows;
total.value = res.total;
loading.value = false;
@ -241,7 +240,6 @@ const submitForm = () => {
if (valid) {
buttonLoading.value = true;
form.value.isDesign = true;
if (form.value.id) {
await updateMonthPlan(form.value).finally(() => (buttonLoading.value = false));
} else {
@ -265,8 +263,10 @@ const handleDelete = async (row?: MonthPlanVO) => {
/** 审核按钮操作 */
const handleAudit = async (row?: MonthPlanVO) => {
proxy.$tab.closePage(proxy.$route);
proxy?.$tab.openPage('/approval/monthPlan/indexEdit', '审核月度产值计划', {
planMonth: row?.planMonth,
id: row?.id,
type: 'update'
});
};

View File

@ -104,6 +104,7 @@ import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
import { useUserStoreHook } from '@/store/modules/user';
import { getMonthInfo, isSubmit } from '@/api/out/monthPlan';
import { id } from 'element-plus/es/locale/index.mjs';
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
@ -169,14 +170,12 @@ const getInfo = () => {
loading.value = true;
buttonLoading.value = false;
nextTick(async () => {
console.log('🚀 ~ routeParams.value:', routeParams.value.businessId);
const projectId = routeParams.value.businessId ? routeParams.value.businessId.split('_')[0] : currentProject.value?.id;
const res = await getMonthInfo({ projectId: projectId, planMonth: routeParams.value.planMonth });
console.log(routeParams.value);
// routeParams.value.businessId ? routeParams.value.businessId.split('_')[0] : routeParams.value.id;
const res = await getMonthInfo({ id: routeParams.value.id.split('_')[0] });
form.value = res.data as any;
console.log('🚀 ~ getInfo ~ form.value:', form.value[0].projectId);
form.value[0].mid = form.value[0].id;
form.value[0].id = form.value[0].projectId + '_' + form.value[0].planMonth;
form.value[0].id = form.value[0].id + '_plan';
loading.value = false;
buttonLoading.value = false;
});
@ -196,7 +195,7 @@ const submitFlow = async () => {
const handleStartWorkFlow = async (data: LeaveForm) => {
try {
submitFormData.value.flowCode = flowCode.value;
submitFormData.value.businessId = currentProject.value?.id + '_' + form.value[0]?.planMonth;
submitFormData.value.businessId = routeParams.value.id + '_plan';
//流程变量
taskVariables.value = {
@ -215,8 +214,6 @@ const handleStartWorkFlow = async (data: LeaveForm) => {
};
//审批记录
const handleApprovalRecord = () => {
console.log(form.value[0]?.id);
approvalRecordRef.value.init(form.value[0]?.id);
};
//提交回调
@ -231,20 +228,12 @@ const approvalVerifyOpen = async () => {
// 图纸上传成功之后 开始提交
const submit = async (status, data) => {
form.value = data;
console.log(form.value);
if (status === 'draft') {
buttonLoading.value = false;
proxy?.$modal.msgSuccess('暂存成功');
proxy.$tab.closePage(proxy.$route);
proxy.$router.go(-1);
} else {
const res = await isSubmit(data[0]?.mid);
if (!res.data) {
proxy?.$modal.msgError('三种计划产值必须填写');
return;
}
if ((form.value[0]?.planAuditStatus === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
flowCode.value = flowCodeOptions[0].value;
dialogVisible.visible = true;
@ -261,12 +250,9 @@ const submit = async (status, data) => {
onMounted(() => {
nextTick(async () => {
routeParams.value = proxy.$route.query;
console.log('🚀 ~ proxy.$route.query:', proxy.$route.query);
reset();
loading.value = false;
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
console.log('🚀 ~ routeParams.value:', routeParams.value);
getInfo();
}
});

View File

@ -85,7 +85,7 @@ const handleQuery = () => {
/** 重置按钮操作 */
const resetQuery = () => {
queryParams.value.month = '';
resetMonth();
handleQuery();
};
// 获取列表
@ -102,7 +102,7 @@ const getList = async () => {
total.value = res.total;
}
};
onMounted(() => {
const resetMonth=()=>{
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = currentDate.getMonth() + 1; // 月份从0开始所以需要加1
@ -110,6 +110,9 @@ onMounted(() => {
// 形成"YYYY-M"格式
const formattedDate = `${year}-${String(month).padStart(2, '0')}`;
queryParams.value.month = formattedDate;
}
onMounted(() => {
resetMonth();
getList();
});

View File

@ -120,17 +120,17 @@
<!-- <el-input v-model="form.projectStructure" placeholder="请输入对应项目结构" /> -->
</el-form-item>
<el-form-item label="预计开始时间" prop="planStartDate">
<el-date-picker clearable v-model="form.planStartDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择预计开始时间" />
<el-date-picker clearable v-model="form.planStartDate" type="date" value-format="YYYY-MM-DD" placeholder="选择预计开始时间" />
</el-form-item>
<el-form-item label="预计结束时间" prop="planEndDate">
<el-date-picker clearable v-model="form.planEndDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="选择预计结束时间" />
<el-date-picker clearable v-model="form.planEndDate" type="date" value-format="YYYY-MM-DD" placeholder="选择预计结束时间" />
</el-form-item>
<el-form-item label="实际开始时间" prop="practicalStartDate">
<el-date-picker
clearable
v-model="form.practicalStartDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择实际开始时间"
/>
</el-form-item>
@ -138,8 +138,8 @@
<el-date-picker
clearable
v-model="form.practicalEndDate"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择实际结束时间"
/>
</el-form-item>

View File

@ -216,7 +216,7 @@ const { queryParams, form, rules } = toRefs(data);
/** 查询进度类别模版列表 */
const getList = async () => {
loading.value = true;
const res = await listProgressCategoryTemplateByParent(activeTab.value);
const res = await listProgressCategoryTemplateByParent(activeTab.value,queryParams.value.name);
const data = proxy?.handleTree<ProgressCategoryTemplateVO>(res.data, 'id', 'parentId');
if (data) {
progressCategoryTemplateList.value = data;

View File

@ -44,11 +44,11 @@
{{ userDetail?.sfzNumber }}
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="身份证号码">
{{ userDetail?.sfzNumber }}
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12">
<el-form-item label="身份证有效开始期">
{{ dayjs(userDetail?.sfzStart).format('YYYY 年 MM 月 DD 日') }}
@ -59,7 +59,7 @@
{{ dayjs(userDetail?.sfzEnd).format('YYYY 年 MM 月 DD 日') }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="24">
<el-form-item label="身份证地址">
{{ userDetail?.sfzSite }}
</el-form-item>

View File

@ -10,7 +10,7 @@
<el-form-item label="地块名称" prop="landName">
<el-input v-model="queryParams.landName" placeholder="请输入地块名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="所属村委会" prop="villageCommittee">
<!-- <el-form-item label="所属村委会" prop="villageCommittee">
<el-input v-model="queryParams.villageCommittee" placeholder="请输入所属村委会" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="设计面积(亩)" prop="designArea">
@ -21,7 +21,7 @@
</el-form-item>
<el-form-item label="农户数(户)" prop="farmerCount">
<el-input v-model="queryParams.farmerCount" type="number" placeholder="请输入农户数" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-form-item> -->
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>

View File

@ -44,11 +44,11 @@
{{ userDetail?.sfzNumber }}
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-col :span="12">
<el-form-item label="身份证号码">
{{ userDetail?.sfzNumber }}
</el-form-item>
</el-col>
</el-col> -->
<el-col :span="12">
<el-form-item label="身份证有效开始期">
{{ dayjs(userDetail?.sfzStart).format('YYYY年 MM 月 DD 日') }}

View File

@ -1,7 +1,6 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
@ -46,43 +45,59 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"
v-hasPermi="['contractor:constructionUser:add']">新增 </el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['contractor:constructionUser:add']">新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
v-hasPermi="['contractor:constructionUser:remove']">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['contractor:constructionUser:remove']"
>
删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['contractor:constructionUser:export']">导出
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['contractor:constructionUser:export']"
>导出
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Edit" :disabled="multiple" @click="statusDialog = true">用户状态编辑
</el-button>
<el-button type="warning" plain icon="Edit" :disabled="multiple" @click="statusDialog = true">用户状态编辑 </el-button>
</el-col>
<el-col :span="1.5">
<el-switch v-model="playCardStatus" class="ml-2" inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" :loading="playCardLoding"
@change="handlePlayCardStatus" inactive-text="一键关闭打卡" active-text="一键开启打卡" />
<el-switch
v-model="playCardStatus"
class="ml-2"
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
:loading="playCardLoding"
@change="handlePlayCardStatus"
inactive-text="一键关闭打卡"
active-text="一键开启打卡"
/>
</el-col>
<el-row @mouseover="informationStatus = true" :gutter="10" @mouseout="informationStatus = false">
<el-col :span="1.5">
<el-button type="success" plain>员工资料 </el-button>
</el-col>
<el-col :span="1.5" v-show="informationStatus">
<el-button type="primary" plain icon="Edit" @click="downloadTemplate"
v-hasPermi="['contractor:constructionUserFile:download']">下载资料模板
<el-button type="primary" plain icon="Edit" @click="downloadTemplate" v-hasPermi="['contractor:constructionUserFile:download']"
>下载资料模板
</el-button>
</el-col>
<el-col :span="1.5" v-show="informationStatus">
<file-upload v-model="filePath" isImportInfo :isShowTip="false"
uploadUrl="/project/constructionUserFile/upload/zip" :limit="1" :file-size="50">
<el-button type="warning" plain icon="Edit"
v-hasPermi="['contractor:constructionUserFile:upload']">导入员工资料 </el-button>
<file-upload
v-model="filePath"
isImportInfo
:isShowTip="false"
uploadUrl="/project/constructionUserFile/upload/zip"
:limit="1"
:file-size="50"
>
<el-button type="warning" plain icon="Edit" v-hasPermi="['contractor:constructionUserFile:upload']">导入员工资料 </el-button>
</file-upload>
</el-col>
</el-row>
@ -120,9 +135,18 @@
</el-table-column>
<el-table-column label="打卡状态" align="center" prop="clock">
<template #default="scope">
<el-switch v-model="scope.row.clock" class="ml-2" inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" active-text="开启" inactive-text="禁用"
:loading="playCardLoding" active-value="0" inactive-value="1" @change="handleClockStatus(scope.row)" />
<el-switch
v-model="scope.row.clock"
class="ml-2"
inline-prompt
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
active-text="开启"
inactive-text="禁用"
:loading="playCardLoding"
active-value="0"
inactive-value="1"
@change="handleClockStatus(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="薪水" align="center" min-width="180">
@ -131,8 +155,7 @@
{{ scope.row.salary ? scope.row.salary : scope.row.standardSalary }}
(<dict-tag :options="wage_measure_unit_type" :value="scope.row.wageMeasureUnit"></dict-tag>)
</span>
<div class="text-blue text-sm cursor-pointer" @click="openSalaryDialog(scope.row)">{{ scope.row.salary ?
'取消变更' : '变更' }}</div>
<div class="text-blue text-sm cursor-pointer" @click="openSalaryDialog(scope.row)">{{ scope.row.salary ? '取消变更' : '变更' }}</div>
</template>
</el-table-column>
<el-table-column label="入场时间" align="center" prop="entryDate" min-width="180" />
@ -146,30 +169,31 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" min-width="300">
<template #default="scope">
<el-space wrap>
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)"
v-hasPermi="['contractor:constructionUser:query']">
<el-button link type="primary" icon="View" @click="handleShowDrawer(scope.row)" v-hasPermi="['contractor:constructionUser:query']">
详情
</el-button>
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['contractor:constructionUser:edit']">
<el-button link type="success" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['contractor:constructionUser:edit']">
修改
</el-button>
<el-button link type="warning" icon="Female" @click="handlePlayCard(scope.row)"> 打卡 </el-button>
<el-button link type="danger" icon="Avatar" @click="handleJoinBlacklist(scope.row)"
v-hasPermi="['contractor:constructionBlacklist:add']">
<el-button
link
type="danger"
icon="Avatar"
@click="handleJoinBlacklist(scope.row)"
v-hasPermi="['contractor:constructionBlacklist:add']"
>
黑名单
</el-button>
<!-- <el-button link type="primary" icon="Switch" @click="handleToggle(scope.row)"> 切换人脸 </el-button> -->
<el-button link type="primary" icon="Switch" @click="handleChange(scope.row)"> 人员迁移 </el-button>
<el-button link type="primary" icon="Switch" @click="handleAssign(scope.row)"> 分配班组 </el-button>
<el-button link type="primary" icon="ChatLineSquare" @click="handleExit(scope.row)"> 入退场记录 </el-button>
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['contractor:constructionUser:remove']">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['contractor:constructionUser:remove']">
删除
</el-button>
<el-tooltip content="红点:部分上传,绿点:已上传,无点:未上传" placement="right" effect="dark">
<el-badge :is-dot="scope.row.fileUploadStatus != '1'"
:type="uploadStatusColor(scope.row.fileUploadStatus)">
<el-badge :is-dot="scope.row.fileUploadStatus != '1'" :type="uploadStatusColor(scope.row.fileUploadStatus)">
<el-button link type="primary" icon="FolderAdd" @click="handleUpload(scope.row)">文件上传 </el-button>
</el-badge>
</el-tooltip>
@ -178,8 +202,7 @@
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改施工人员对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="930px" append-to-body>
@ -231,14 +254,12 @@
</div>
<div class="el-col el-col-12">
<el-form-item label="身份证有效开始期" prop="sfzStart">
<el-date-picker clearable v-model="form.sfzStart" type="date" value-format="YYYY-MM-DD"
placeholder="请输入身份证有效开始期" />
<el-date-picker clearable v-model="form.sfzStart" type="date" value-format="YYYY-MM-DD" placeholder="请输入身份证有效开始期" />
</el-form-item>
</div>
<div class="el-col el-col-12">
<el-form-item label="身份证有效结束期" prop="sfzEnd">
<el-date-picker clearable v-model="form.sfzEnd" type="date" value-format="YYYY-MM-DD"
placeholder="请输入身份证有效结束期" />
<el-date-picker clearable v-model="form.sfzEnd" type="date" value-format="YYYY-MM-DD" placeholder="请输入身份证有效结束期" />
</el-form-item>
</div>
<div class="el-col el-col-12">
@ -248,8 +269,7 @@
</div>
<div class="el-col el-col-12">
<el-form-item label="身份证出生日期" prop="sfzBirth">
<el-date-picker clearable v-model="form.sfzBirth" type="date" value-format="YYYY-MM-DD"
placeholder="请输入身份证出生日期" />
<el-date-picker clearable v-model="form.sfzBirth" type="date" value-format="YYYY-MM-DD" placeholder="请输入身份证出生日期" />
</el-form-item>
</div>
<div class="el-col el-col-12">
@ -302,16 +322,14 @@
<div class="el-col el-col-12">
<el-form-item label="打卡" prop="clock">
<el-select v-model="form.clock" clearable placeholder="请选择打卡状态">
<el-option v-for="item in user_clock_type" :key="item.value" :label="item.label"
:value="item.value" />
<el-option v-for="item in user_clock_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</div>
<div class="el-col el-col-12">
<el-form-item label="结算方式" prop="wageMeasureUnit">
<el-select v-model="form.wageMeasureUnit" clearable placeholder="请选择结算方式">
<el-option v-for="item in wage_measure_unit_type" :key="item.value" :label="item.label"
:value="item.value" />
<el-option v-for="item in wage_measure_unit_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</div>
@ -340,8 +358,7 @@
</el-select>
</el-form-item>
<el-form-item label="分包单位" label-width="130px">
<el-select v-model="skipObject.contractorId" :disabled="!skipObject.projectId" placeholder="请选择分包单位"
style="width: 240px">
<el-select v-model="skipObject.contractorId" :disabled="!skipObject.projectId" placeholder="请选择分包单位" style="width: 240px">
<el-option v-for="item in contractorList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
@ -356,8 +373,7 @@
<div class="image_upload" v-for="(item, index) in uploadPath" :key="item.value">
<div class="title">{{ item.label }}</div>
<div class="file_upload_all" v-if="item.value != 7">
<file-upload v-model="item.path" isConstruction :isShowTip="false" :limit="10" :file-type="['pdf']"
:file-size="50" />
<file-upload v-model="item.path" isConstruction show-file-list :isShowTip="false" :limit="10" :file-type="['pdf']" :file-size="50" />
</div>
</div>
<template #footer>
@ -376,7 +392,8 @@
</el-form>
</div>
<template #footer>
<span><el-button type="primary" @click="submitForm">保存</el-button>
<span
><el-button type="primary" @click="submitForm">保存</el-button>
<el-button @click="showFaceDrawer = false">取消</el-button>
</span>
</template>
@ -388,7 +405,8 @@
</el-select>
</el-form-item>
<template #footer>
<span><el-button type="primary" @click="handleEdit">保存</el-button>
<span
><el-button type="primary" @click="handleEdit">保存</el-button>
<el-button @click="statusDialog = false">取消</el-button>
</span>
</template>
@ -412,8 +430,8 @@
<el-timeline-item color="rgb(255, 73, 73)">
<div class="mb">{{ '退场时间:' + item.entryDate }}</div>
<div class="pl-xl">
<span class="text-coolgray font-bold">退场文件<image-preview v-for="itm in item.pathUrl" :src="itm"
width="100px" class="mr" /></span><br />
<span class="text-coolgray font-bold">退场文件<image-preview v-for="itm in item.pathUrl" :src="itm" width="100px" class="mr" /></span
><br />
<p class="mt text-coolgray">
备注<span class="text-blue">{{ item.remark }}</span>
</p>
@ -441,8 +459,11 @@
<el-date-picker v-model="monthValue" type="month" placeholder="请选择月份" @change="handleMonth" />
</template>
<template #date-cell="{ data }">
<div class="w100% h100% position-relative m-0 monthDay" :class="data.isSelected ? 'is-selected' : ''"
@click="handleViewPlayCard(playCardIdx(data), data)">
<div
class="w100% h100% position-relative m-0 monthDay"
:class="data.isSelected ? 'is-selected' : ''"
@click="handleViewPlayCard(playCardIdx(data), data)"
>
{{ data.day.split('-').slice(1).join('-') }}
<div :style="{ background: playCardColor(data) }" v-if="playCardIdx(data) != -1"></div>
</div>
@ -461,8 +482,12 @@
</el-select>
</el-form-item>
<el-form-item label="班组" label-width="130px">
<el-select v-model="personnelAllocationObject.teamId" :disabled="!personnelAllocationObject.projectId" placeholder="请选择分包单位"
style="width: 240px">
<el-select
v-model="personnelAllocationObject.teamId"
:disabled="!personnelAllocationObject.projectId"
placeholder="请选择班组"
style="width: 240px"
>
<el-option v-for="item in teamList" :key="item.id" :label="item.teamName" :value="item.id" />
</el-select>
</el-form-item>
@ -586,7 +611,7 @@ const personnelAllocationObject = reactive({
memberId: null,
projectId: '',
teamId: '',
postId: '',
postId: ''
});
const contractorList = ref<Array<skipTeamType>>([]);
@ -974,7 +999,7 @@ const handleExit = async (row: ConstructionUserVO) => {
//上传按钮
const handleUpload = async (row: ConstructionUserVO) => {
const _id = row?.id || ids.value[0];
const _id = row?.sysUserId;
currentUserId.value = _id;
const res = await listConstructionUserFile({ userId: _id });
fileList.value = res.data;
@ -1110,14 +1135,17 @@ const listeningProject = watch(
const handleAssign = async (row: ConstructionUserVO) => {
const _id = row?.id || ids.value[0];
currentUserId.value = _id;
personnelAllocationObject.projectId = '';
personnelAllocationObject.postId = '';
personnelAllocationObject.teamId = '';
personnelAllocationObject.memberId = row?.sysUserId;
skipName.value = row?.userName;
personnelAllocation.value = true;
};
// 选择项目1
const selectProject1 = (e: any) => {
// 请求班组
getTeamList(personnelAllocationObject.projectId);
};
const getTeamList = async (projectId) => {
const res = await TeamList({

View File

@ -14,15 +14,6 @@
<el-option v-for="dict in safety_question_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="题目内容" prop="questionContent">
<el-input v-model="queryParams.questionContent" placeholder="请输入题目内容" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="选项" prop="options">
<el-input v-model="queryParams.options" placeholder="请输入选项" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="正确答案" prop="correctAnswer">
<el-input v-model="queryParams.correctAnswer" placeholder="请输入正确答案" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@ -38,32 +29,18 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['safety:questionBank:add']"> 新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['safety:questionBank:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['safety:questionBank:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['safety:questionBank:export']">导出 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="questionBankList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键id" align="center" prop="id" v-if="true" />
<el-table-column label="题目类别" align="center" prop="categoryType">
<el-table v-loading="loading" :data="questionBankList">
<el-table-column label="序号" align="center" type="index" width="80" />
<el-table-column label="题目类别" align="center" width="100" prop="categoryType">
<template #default="scope">
<dict-tag :options="safety_question_category_type" :value="scope.row.categoryType" />
</template>
</el-table-column>
<el-table-column label="题目类型" align="center" prop="questionType">
<el-table-column label="题目类型" align="center" width="100" prop="questionType">
<template #default="scope">
<dict-tag :options="safety_question_type" :value="scope.row.questionType" />
</template>
@ -73,16 +50,11 @@
<el-table-column label="正确答案" align="center" prop="correctAnswer" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['safety:questionBank:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['safety:questionBank:remove']"></el-button>
</el-tooltip>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['safety:questionBank:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['safety:questionBank:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改题库对话框 -->

View File

@ -1,7 +1,6 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
@ -31,23 +30,27 @@
:上传压缩包内的文件夹名称需设置为姓名-身份证-满分-得分-及格分 <br />
例如:小明-5130112333654X-100-59-60
</template>
<file-upload :limit="1" v-model:model-value="filePath" isImportInfo :fileType="['zip']"
uploadUrl="/safety/questionUserAnswer/upload/zip" :file-size="5000"
:data="{ projectId: currentProject.id }"><el-button type="success" plain
icon="Upload">上传线下安全考试</el-button></file-upload>
<file-upload
:limit="1"
v-model:model-value="filePath"
isImportInfo
:fileType="['zip']"
uploadUrl="/safety/wgzQuestionSave/upload/zip"
:file-size="5000"
:data="{ projectId: currentProject.id }"
><el-button type="success" plain icon="Upload">上传线下安全考试</el-button></file-upload
>
</el-tooltip>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Download" :disabled="single"
@click="handleDownload()">批量下载试卷</el-button>
<el-button type="primary" plain icon="Download" :disabled="single" @click="handleDownload()">批量下载试卷</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="questionUserAnswerList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键id" align="center" prop="id" v-if="false" />
<el-table-column type="index" label="序号" width="80" align="center" />
<el-table-column label="姓名" align="center" prop="userName" />
<el-table-column label="及格线/总分" align="center" prop="pass" />
<el-table-column label="得分" align="center" prop="score" />
@ -59,21 +62,19 @@
<dict-tag :options="user_exam_type" :value="scope.row.examType" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-link type="primary" :underline="false" :href="scope.row.fileUrl[0]" target="_blank">
<!-- <el-link type="primary" :underline="false" :href="scope.row.path[0]" target="_blank">
<el-button link type="primary" icon="View">预览试卷</el-button>
</el-link>
<el-button link type="primary" icon="Download" @click="downloadOssOne(scope.row)"
v-hasPermi="['system:oss:download']">下载试卷</el-button>
</el-link> -->
<el-button link type="primary" icon="Download" @click="downloadOssOne(scope.row)" v-hasPermi="['system:oss:download']"
>下载试卷</el-button
>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
</div>
</template>
@ -196,35 +197,15 @@ const handleSelectionChange = (selection: QuestionUserAnswerVO[]) => {
multiple.value = !selection.length;
};
/** 修改按钮操作 */
// const handleUpdate = async (row?: QuestionUserAnswerVO) => {
// reset();
// const _id = row?.id || ids.value[0];
// const res = await getQuestionUserAnswer(_id);
// Object.assign(form.value, res.data);
// dialog.visible = true;
// dialog.title = '修改用户试卷存储';
// };
/** 批量下载按钮操作 */
const handleDownload = async () => {
const _ids = ids.value;
await downLoadOss({ idList: _ids }, '/safety/questionUserAnswer/exportFile', '安全考试.zip');
await downLoadOss({ idList: _ids }, '/safety/wgzQuestionSave/exportFile', '安全考试.zip');
};
/** 下载单个按钮操作 */
const downloadOssOne = async (row?: QuestionUserAnswerVO) => {
await download.oss(row?.file);
};
// const fileWatch = watch(
// () => filePath.value,
// (nid, oid) => {
// uploadQuestionUserAnswer({ file: filePath.value, projectId: currentProject.value?.id }).then((res) => {
// console.log(res);
// });
// }
// );
//监听项目id刷新数据
const listeningProject = watch(
() => currentProject.value?.id,

View File

@ -22,38 +22,21 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['safety:questionsCategory:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['safety:questionsCategory:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['safety:questionsCategory:remove']"
>删除</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="questionsCategoryList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table v-loading="loading" :data="questionsCategoryList">
<el-table-column label="序号" align="center" type="index" width="100" />
<el-table-column label="题库类别" align="center" prop="categoryName" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['safety:questionsCategory:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['safety:questionsCategory:remove']"
></el-button>
</el-tooltip>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['safety:questionsCategory:edit']"
>修改</el-button
>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['safety:questionsCategory:remove']"
>删除</el-button
>
</template>
</el-table-column>
</el-table>

View File

@ -1,309 +1,220 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="单选题" prop="singleChoice">
<el-input v-model="queryParams.singleChoice" placeholder="请输入单选题" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="单选分数" prop="singleScore">
<el-input v-model="queryParams.singleScore" placeholder="请输入单选分数" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="多选题" prop="multipleChoice">
<el-input v-model="queryParams.multipleChoice" placeholder="请输入多选题" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="多选分数" prop="multipleScore">
<el-input v-model="queryParams.multipleScore" placeholder="请输入多选分数" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="判断题" prop="estimate">
<el-input v-model="queryParams.estimate" placeholder="请输入判断题" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="判断分数" prop="estimateScore">
<el-input v-model="queryParams.estimateScore" placeholder="请输入判断分数" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="满分" prop="fullMark">
<el-input v-model="queryParams.fullMark" placeholder="请输入满分" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="及格线" prop="passScore">
<el-input v-model="queryParams.passScore" placeholder="请输入及格线" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="答题最大时间" prop="answerTime">
<el-input v-model="queryParams.answerTime" placeholder="请输入答题最大时间" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="container p-4 md:p-6">
<el-card shadow="hover" class="config-card transition-all duration-300 hover:shadow-lg">
<div class="card-header mb-4">
<h2 class="text-xl font-semibold text-gray-800">题库配置</h2>
<p class="text-gray-500 text-sm">设置各类题型数量分值及考试参数</p>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['safety:questionsConfig:add']"> 新增 </el-button>
<el-form :model="form" label-width="120px" ref="formRef" class="config-form">
<el-row :gutter="20">
<!-- 单选题设置 -->
<el-col :span="12" class="form-item-col">
<el-form-item label="单选题(道)" :rules="[{ required: true, message: '单选题数量不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.singleChoice" min="0" class="transition-all" placeholder="请输入数量" />
</el-form-item>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['safety:questionsConfig:edit']"
>修改
</el-button>
<el-col :span="12" class="form-item-col">
<el-form-item label="单选分数" :rules="[{ required: true, message: '单选分数不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.singleScore" min="0" class="transition-all" placeholder="每题分数" />
</el-form-item>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['safety:questionsConfig:remove']"
>删除
</el-button>
<!-- 多选题设置 -->
<el-col :span="12" class="form-item-col">
<el-form-item label="多选题(道)" :rules="[{ required: true, message: '多选题数量不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.multipleChoice" min="0" class="transition-all" placeholder="请输入数量" />
</el-form-item>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['safety:questionsConfig:export']">导出 </el-button>
<el-col :span="12" class="form-item-col">
<el-form-item label="多选分数" :rules="[{ required: true, message: '多选分数不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.multipleScore" min="0" class="transition-all" placeholder="每题分数" />
</el-form-item>
</el-col>
<!-- 判断题设置 -->
<el-col :span="12" class="form-item-col">
<el-form-item label="判断题(道)" :rules="[{ required: true, message: '判断题数量不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.estimate" min="0" class="transition-all" placeholder="请输入数量" />
</el-form-item>
</el-col>
<el-col :span="12" class="form-item-col">
<el-form-item label="判断分数" :rules="[{ required: true, message: '判断分数不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.estimateScore" min="0" class="transition-all" placeholder="每题分数" />
</el-form-item>
</el-col>
<!-- 分数设置 -->
<el-col :span="12" class="form-item-col">
<el-form-item label="及格分数" :rules="[{ required: true, message: '及格分数不能为空', trigger: 'blur' }]">
<el-input
type="number"
v-model="form.passingScore"
min="0"
:max="form.fullMark"
@change="handlePassingScoreChange"
class="transition-all"
placeholder="请输入及格分数"
/>
</el-form-item>
</el-col>
<el-col :span="12" class="form-item-col">
<el-form-item label="满分">
<el-input type="number" v-model="form.fullMark" disabled class="bg-gray-50" />
</el-form-item>
</el-col>
<!-- 时间设置 -->
<el-col :span="12" class="form-item-col">
<el-form-item label="答题时间(分钟)" :rules="[{ required: true, message: '答题时间不能为空', trigger: 'blur' }]">
<el-input type="number" v-model="form.answerTime" min="0" class="transition-all" placeholder="请输入时间" />
</el-form-item>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="questionsConfigList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键id" align="center" prop="id" v-if="true" />
<el-table-column label="单选题" align="center" prop="singleChoice" />
<el-table-column label="单选分数" align="center" prop="singleScore" />
<el-table-column label="多选题" align="center" prop="multipleChoice" />
<el-table-column label="多选分数" align="center" prop="multipleScore" />
<el-table-column label="判断题" align="center" prop="estimate" />
<el-table-column label="判断分数" align="center" prop="estimateScore" />
<el-table-column label="满分" align="center" prop="fullMark" />
<el-table-column label="及格线" align="center" prop="passScore" />
<el-table-column label="答题最大时间" align="center" prop="answerTime" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['safety:questionsConfig:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['safety:questionsConfig:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改题库配置对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="questionsConfigFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="单选题" prop="singleChoice">
<el-input v-model="form.singleChoice" placeholder="请输入单选题" />
</el-form-item>
<el-form-item label="单选分数" prop="singleScore">
<el-input v-model="form.singleScore" placeholder="请输入单选分数" />
</el-form-item>
<el-form-item label="多选题" prop="multipleChoice">
<el-input v-model="form.multipleChoice" placeholder="请输入多选题" />
</el-form-item>
<el-form-item label="多选分数" prop="multipleScore">
<el-input v-model="form.multipleScore" placeholder="请输入多选分数" />
</el-form-item>
<el-form-item label="判断题" prop="estimate">
<el-input v-model="form.estimate" placeholder="请输入判断题" />
</el-form-item>
<el-form-item label="判断分数" prop="estimateScore">
<el-input v-model="form.estimateScore" placeholder="请输入判断分数" />
</el-form-item>
<el-form-item label="满分" prop="fullMark">
<el-input v-model="form.fullMark" placeholder="请输入满分" />
</el-form-item>
<el-form-item label="及格线" prop="passScore">
<el-input v-model="form.passScore" placeholder="请输入及格线" />
</el-form-item>
<el-form-item label="答题最大时间" prop="answerTime">
<el-input v-model="form.answerTime" placeholder="请输入答题最大时间" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
<div class="form-actions flex justify-center mt-6">
<el-button type="primary" @click="onSubmit" :loading="buttonLoading" class="px-8 transition-all hover:scale-105"> 保存配置 </el-button>
</div>
</template>
</el-dialog>
</el-card>
</div>
</template>
<script setup name="QuestionsConfig" lang="ts">
import { addQuestionsConfig, delQuestionsConfig, getQuestionsConfig, listQuestionsConfig, updateQuestionsConfig } from '@/api/safety/questionsConfig';
import { QuestionsConfigForm, QuestionsConfigQuery, QuestionsConfigVO } from '@/api/safety/questionsConfig/types';
import { ref, reactive, computed, onMounted, getCurrentInstance } from 'vue';
import { ElFormInstance, ComponentInternalInstance } from 'element-plus';
import { getQuestionsConfig, updateQuestionsConfig } from '@/api/safety/questionsConfig';
import { QuestionsConfigForm} from '@/api/safety/questionsConfig/types';
import { useUserStoreHook } from '@/store/modules/user';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
// 获取用户信息
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const questionsConfigList = ref<QuestionsConfigVO[]>([]);
// 表单相关
const formRef = ref<ElFormInstance>();
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const questionsConfigFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: QuestionsConfigForm = {
const form = reactive<QuestionsConfigForm>({
id: undefined,
projectId: currentProject.value?.id,
singleChoice: undefined,
singleScore: undefined,
multipleChoice: undefined,
multipleScore: undefined,
estimate: undefined,
estimateScore: undefined,
fullMark: undefined,
passScore: undefined,
answerTime: undefined
};
const data = reactive<PageData<QuestionsConfigForm, QuestionsConfigQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
singleChoice: undefined,
singleScore: undefined,
multipleChoice: undefined,
multipleScore: undefined,
estimate: undefined,
estimateScore: undefined,
fullMark: undefined,
passScore: undefined,
answerTime: undefined,
params: {}
},
rules: {
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }],
singleChoice: [{ required: true, message: '单选题不能为空', trigger: 'blur' }],
singleScore: [{ required: true, message: '单选分数不能为空', trigger: 'blur' }],
multipleChoice: [{ required: true, message: '多选题不能为空', trigger: 'blur' }],
multipleScore: [{ required: true, message: '多选分数不能为空', trigger: 'blur' }],
estimate: [{ required: true, message: '判断题不能为空', trigger: 'blur' }],
estimateScore: [{ required: true, message: '判断分数不能为空', trigger: 'blur' }],
fullMark: [{ required: true, message: '满分不能为空', trigger: 'blur' }],
passScore: [{ required: true, message: '及格线不能为空', trigger: 'blur' }],
answerTime: [{ required: true, message: '答题最大时间不能为空', trigger: 'blur' }]
}
singleChoice: 0,
singleScore: 0,
multipleChoice: 0,
multipleScore: 0,
estimate: 0,
estimateScore: 0,
fullMark: 0,
passScore: 0,
answerTime: 0,
passingScore: 0
});
const { queryParams, form, rules } = toRefs(data);
// 计算满分
const calculateFullMark = () => {
form.fullMark =
(form.singleChoice || 0) * (form.singleScore || 0) +
(form.multipleChoice || 0) * (form.multipleScore || 0) +
(form.estimate || 0) * (form.estimateScore || 0);
/** 查询题库配置列表 */
const getList = async () => {
loading.value = true;
const res = await listQuestionsConfig(queryParams.value);
questionsConfigList.value = res.rows;
total.value = res.total;
loading.value = false;
// 确保及格分不超过满分
if (form.passingScore > form.fullMark) {
form.passingScore = form.fullMark;
}
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
// 监听分数变化,自动计算满分
['singleChoice', 'singleScore', 'multipleChoice', 'multipleScore', 'estimate', 'estimateScore'].forEach((field) => {
watch(() => form[field], calculateFullMark);
});
// 处理及格分变化
const handlePassingScoreChange = (val: number) => {
if (val >= form.fullMark) {
form.passingScore = form.fullMark;
}
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
questionsConfigFormRef.value?.resetFields();
// 获取配置详情
const getDetail = () => {
getQuestionsConfig(1).then((res: any) => {
if (res.code == 200 && res.data) {
Object.assign(form, res.data);
calculateFullMark(); // 确保满分计算正确
}
});
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: QuestionsConfigVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加题库配置';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: QuestionsConfigVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getQuestionsConfig(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改题库配置';
};
/** 提交按钮 */
const submitForm = () => {
questionsConfigFormRef.value?.validate(async (valid: boolean) => {
// 提交表单
const onSubmit = () => {
formRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateQuestionsConfig(form.value).finally(() => (buttonLoading.value = false));
} else {
await addQuestionsConfig(form.value).finally(() => (buttonLoading.value = false));
try {
await updateQuestionsConfig(form);
// 显示成功消息假设使用element-plus的message组件
ElMessage.success('配置保存成功');
getDetail(); // 重新获取最新配置
} catch (error) {
ElMessage.error('保存失败,请重试');
} finally {
buttonLoading.value = false;
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: QuestionsConfigVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除题库配置编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delQuestionsConfig(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'safety/questionsConfig/export',
{
...queryParams.value
},
`questionsConfig_${new Date().getTime()}.xlsx`
);
};
// 页面加载时获取数据
onMounted(() => {
getList();
getDetail();
});
</script>
<style lang="scss" scoped>
.container {
max-width: 800px;
margin: 0 auto;
padding-top: 20px;
}
.config-card {
border-radius: 12px;
overflow: hidden;
}
.card-header {
border-bottom: 1px solid #f0f0f0;
padding-bottom: 12px;
}
.form-item-col {
margin-bottom: 16px;
}
.form-actions {
padding: 16px;
border-top: 1px solid #f0f0f0;
margin-top: 20px;
}
// 输入框聚焦效果
::v-deep .el-input__wrapper:focus-within {
box-shadow: 0 0 0 2px rgba(48, 163, 255, 0.2);
}
// 响应式调整
@media (max-width: 768px) {
.el-col {
&:span-12 {
width: 100% !important;
}
}
.card-header {
text-align: center;
}
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="p-2 editInfo">
<el-form label-position="top" ref="userFormRef" :model="form" :rules="rules" label-width="80px">
<el-form label-position="top" ref="userFormRef" :model="form" :rules="rules" label-width="80px" size="large">
<el-row>
<el-col :span="10">
<el-form-item label="用户昵称" prop="nickName">
@ -70,15 +70,15 @@
</el-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
<el-input v-model="form.remark" type="textarea" :autosize="{ minRows: 3, maxRows: 3 }" placeholder="请输入内容"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- <div class="box_submit">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel()"> </el-button>
</div> -->
<div class="box_submit">
<el-button size="large" @click="cancel()"> </el-button>
<!-- <el-button size="large" type="primary" @click="submitForm"> </el-button> -->
</div>
</div>
</template>
@ -192,12 +192,12 @@ async function handleDeptChange(value: number | string) {
];
}
const submitForm = () => {
const submitForm = (cb) => {
userFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
proxy?.$modal.msgSuccess('操作成功');
proxy?.$emit('submit', false);
// form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
// proxy?.$modal.msgSuccess('操作成功');
cb();
}
});
};
@ -243,16 +243,16 @@ const getInfoForm = () => {
onMounted(() => {
getDeptTree();
});
defineExpose({ open, getInfoForm });
defineExpose({ open, getInfoForm, submitForm });
</script>
<style lang="scss" scoped>
.editInfo {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
.box_submit {
position: absolute;
right: 10px;
bottom: 10px;
align-self: flex-end;
display: flex;
gap: 10px;
}
}
</style>

View File

@ -11,7 +11,7 @@
</el-table>
</div>
</div>
<div class="title_detail" style="margin-top: 20px">
<div class="title_detail" style="margin-top: 10px">
<span>选择或修改当前角色信息</span>
<div style="margin-top: 10px" class="box_detail">
<!-- 项目列表选择区 -->
@ -34,7 +34,7 @@
</div>
<!-- 角色分配区 -->
<div class="post_list">
<span>关联项目角色分配</span>
<div class="list_title">关联项目角色分配</div>
<div v-if="selectedProjects.length === 0" class="no-selection">请从左侧选择项目进行角色分配</div>
<div v-for="(project, index) in selectedProjects" :key="project.id" class="project-role-container">
<div class="project-header">
@ -64,8 +64,8 @@
</div>
</div>
<div class="box_submit">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel()"> </el-button>
<el-button size="large" @click="cancel()"> </el-button>
<el-button size="large" type="primary" @click="submitForm">保存角色信息</el-button>
</div>
</div>
</template>
@ -219,7 +219,19 @@ const removeProject = (projectId: number | string) => {
// 提交表单
const submitForm = async () => {
// 整理项目角色数据
if (form.value.projectRoles.length == 0) {
console.log(selectedProjects.value);
if (selectedProjects.value.length == 0) {
proxy?.$modal.msgWarning('请选择项目角色');
return;
}
let flag = false;
selectedProjects.value.forEach((project) => {
if (project.appRoles.length > 0 || project.webRoles.length > 0) {
flag = true;
}
});
if (!flag) {
proxy?.$modal.msgWarning('请选择项目角色');
return;
}
@ -328,10 +340,12 @@ defineExpose({ open });
<style lang="scss">
.roleInfo {
position: relative;
height: 100%;
padding-bottom: 60px;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 12px;
.title_detail {
> span {
@ -359,7 +373,7 @@ defineExpose({ open });
.project_list {
width: 320px;
background-color: #fff;
border: 1px solid #eee;
.project-items {
margin-top: 10px;
@ -374,8 +388,7 @@ defineExpose({ open });
border: 1px solid #eee;
&:hover {
background-color: #f5f7fa;
border-color: #e4e7ed;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.project-item-content {
@ -403,7 +416,11 @@ defineExpose({ open });
.post_list {
flex: 1;
background-color: #fff;
border: 1px solid #eee;
.list_title {
margin-bottom: 10px;
}
.no-selection {
height: 100%;
@ -417,9 +434,9 @@ defineExpose({ open });
.project-role-container {
padding: 15px;
margin-bottom: 15px;
background-color: #f9f9f9;
// background-color: #f9f9f9;
border-radius: 4px;
border: 1px solid #f0f0f0;
border: 1px solid rgb(229 231 235);
.project-header {
display: flex;
@ -445,7 +462,9 @@ defineExpose({ open });
.role-assignment {
.role-group {
margin-bottom: 15px;
display: flex;
flex-direction: column;
margin-bottom: 10px;
.role-label {
display: inline-block;
@ -471,9 +490,7 @@ defineExpose({ open });
}
.box_submit {
position: absolute;
right: 20px;
bottom: 0px;
align-self: flex-end;
display: flex;
gap: 10px;
}

View File

@ -154,11 +154,26 @@
</el-row>
<!-- 添加或修改用户配置对话框 -->
<el-dialog draggable ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="1300px" append-to-body @close="closeDialog">
<el-dialog
draggable
ref="formDialogRef"
style="background: rgb(249, 250, 251)"
v-model="dialog.visible"
:title="dialog.title"
width="1300px"
append-to-body
@close="closeDialog"
>
<div class="boxDetial">
<div class="tab_info">
<span @click="onTab(1)" :class="{ active: type == 1 }">基本资料</span>
<span @click="onTab(2)" :class="{ active: type == 2 }">角色信息</span>
<div class="tab_item" @click="onTab(1)" :class="{ active: type == 1 }">
<Avatar style="width: 1em; height: 1em; margin-right: 8px" :style="{ color: type == 1 ? '#1890ff' : '#000' }" />
<span>基本资料</span>
</div>
<div class="tab_item" @click="onTab(2)" :class="{ active: type == 2 }">
<Key style="width: 1em; height: 1em; margin-right: 8px" :style="{ color: type == 2 ? '#1890ff' : '#000' }" />
<span>角色信息</span>
</div>
</div>
<div class="tab_content" v-show="type == 1">
<editInfo ref="editInfoRef" @close="dialog.visible = false" @submit="getList" @setDeptId="setDeptId"></editInfo>
@ -232,6 +247,7 @@ import ShuttleFrame from '../../project/projectRelevancy/component/ShuttleFrame.
import { listProject } from '@/api/project/project';
import editInfo from './comm/editInfo.vue';
import roleInfo from './comm/roleInfo.vue';
import { color } from 'echarts';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
@ -690,14 +706,21 @@ const uploadCert = async () => {
certDialog.value = false;
proxy?.$modal.msgSuccess('上传证书目录成功');
};
const onTab = (val) => {
type.value = val;
const onTab = (val: number) => {
if (val == 2) {
// 查看基本信息
editInfoRef.value?.submitForm((res) => {
type.value = val;
let obj = editInfoRef.value?.getInfoForm();
form.value = obj;
console.log(obj);
nextTick(() => {
roleInfoRef.value?.open(form.value, deptIdRole.value);
});
});
} else {
type.value = val;
}
};
</script>
@ -706,21 +729,32 @@ const onTab = (val) => {
.boxDetial {
display: flex;
justify-content: space-between;
align-items: center;
align-items: start;
height: 680px;
gap: 20px;
.tab_info {
height: 100%;
height: 40%;
width: 200px;
background: #f0f2f5;
padding: 10px;
background: #fff;
padding: 30px 10px;
text-align: center;
display: flex;
flex-direction: column;
border-radius: 0.5rem;
font-size: 18px;
> span {
.tab_item {
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
margin-bottom: 10px;
padding: 5px 0;
cursor: pointer;
}
.tab_item:hover {
background-color: rgb(249, 250, 251);
}
.active {
color: #1890ff;
}
@ -729,7 +763,8 @@ const onTab = (val) => {
height: 100%;
width: calc(100% - 200px);
padding: 20px 10px;
background: #ccc;
background: #fff;
border-radius: 0.5rem;
}
}
</style>

View File

@ -59,10 +59,12 @@
</transition>
<el-card shadow="never" class="mb8">
<el-table ref="tableAllRef" v-loading="loading" :data="tableData" row-key="id" border lazy :expand-row-keys="expandRowKeys">
<el-table-column prop="num" label="编号" />
<el-table-column prop="name" label="工程或费用名称" />
<el-table-column prop="num" label="编号" align="center" />
<el-table-column prop="name" label="工程或费用名称" align="center" />
<el-table-column prop="unit" label="单位" align="center" />
<el-table-column prop="supplier" label="供货单位" align="center" v-if="activeTab == '3'" />
<el-table-column prop="contractNumber" label="合同编号" align="center" v-if="activeTab == '3'" />
<el-table-column prop="specification" label="规格" align="center" />
<el-table-column prop="quantity" label="数量" align="center">
<template #default="scope">

View File

@ -23,22 +23,24 @@
{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" />
<el-table-column prop="content" label="内容" />
<el-table-column prop="price" label="限价" />
<el-table-column prop="bidd">
<el-table-column prop="name" label="名称" align="center" />
<el-table-column prop="content" label="内容" align="center" />
<el-table-column prop="price" label="限价" align="center" />
<el-table-column prop="bidd" align="center">
<template #header> <span style="color: red">*</span>招标文件 </template>
<template #default="scope">
<el-button type="primary" link v-hasPermi="['tender:biddingPlan:getAnnex']" @click="biddView(scope.row)">查看文件</el-button>
<el-button type="primary" link v-hasPermi="['tender:biddingPlan:getAnnex']" @click="biddView(scope.row)" v-if="scope.row.annexCount > 0"
>查看文件({{ scope.row.annexCount }})</el-button
>
</template>
</el-table-column>
<el-table-column prop="winningBidder">
<el-table-column prop="winningBidder" align="center">
<template #header> <span style="color: red">*</span>中标单位 </template>
<template #default="scope">
{{ scope.row.winningBidder }}
</template>
</el-table-column>
<el-table-column prop="bidFileName">
<el-table-column prop="bidFileName" align="center">
<template #header> <span style="color: red">*</span>中标文件 </template>
<template #default="scope">
<el-button type="primary" link @click="openPdf(scope.row.bidFile)">{{ scope.row.bidFileName }} </el-button>
@ -198,9 +200,11 @@
? activeTab == 2
? 0
: ''
: (scope.row.quantity ? Number(scope.row.quantity) : 0) -
: (
(scope.row.quantity ? Number(scope.row.quantity) : 0) -
(scope.row.selectNum ? Number(scope.row.selectNum) : 0) -
(scope.row.useQuantity ? Number(scope.row.useQuantity) : 0)
).toFixed(2)
}}
</template>
</el-table-column>

View File

@ -34,15 +34,13 @@
<el-table-column :show-overflow-tooltip="true" prop="flowName" align="center" label="流程定义名称"></el-table-column>
<el-table-column align="center" prop="flowCode" label="流程定义编码"></el-table-column>
<el-table-column align="center" prop="categoryName" label="流程分类"></el-table-column>
<el-table-column align="center" prop="version" label="版本号" width="90">
<template #default="scope"> v{{ scope.row.version }}.0</template>
</el-table-column>
<el-table-column align="center" prop="nodeName" label="任务名称"></el-table-column>
<el-table-column align="center" label="流程状态" min-width="70">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus"></dict-tag>
</template>
</el-table-column>
<el-table-column align="center" prop="updateTime" label="更新时间" width="150"></el-table-column>
<el-table-column label="操作" align="center" width="200">
<template #default="scope">
<el-button type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button>