first commit
This commit is contained in:
244
src/views/design/Professional/index.vue
Normal file
244
src/views/design/Professional/index.vue
Normal file
@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<div class="p-6 bg-gray-50 Professional">
|
||||
<transition>
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="never">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="电话" prop="phone">
|
||||
<el-input v-model="queryParams.phone" 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">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="professionalList">
|
||||
<el-table-column label="序号" align="center" type="index" width="100" />
|
||||
<el-table-column label="提资人" align="center" prop="userName" />
|
||||
<el-table-column label="专业" align="center" prop="userMajorName" />
|
||||
<el-table-column label="电话" align="center" prop="phone" />
|
||||
<el-table-column label="邮箱" align="center" prop="email" />
|
||||
<el-table-column label="流程状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:extract:query']">审核</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="scope.row.status === 'finish'">
|
||||
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['design:extract:export']"
|
||||
>导出</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
link
|
||||
type="warning"
|
||||
icon="View"
|
||||
v-if="scope.row.status != 'draft'"
|
||||
v-hasPermi="['design:extract:query']"
|
||||
@click="handleViewInfo(scope.row)"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
link
|
||||
type="warning"
|
||||
icon="View"
|
||||
v-if="scope.row.status != 'draft'"
|
||||
v-hasPermi="['design:extract:query']"
|
||||
@click="handleFile(scope.row)"
|
||||
>查看文件</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</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="提取文件列表" v-model="viewVisible" width="500px">
|
||||
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
|
||||
<el-table-column prop="fileName" label="文件名称" align="center">
|
||||
<template #default="scope">
|
||||
<el-link
|
||||
:key="scope.row.fileId"
|
||||
:href="scope.row.fileUrl"
|
||||
target="_blank"
|
||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||
:underline="false"
|
||||
>
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否变更" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.type == 1 ? 'success' : 'info'">{{ scope.row.type == 1 ? '否' : '是' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">{{ scope.row.status == 1 ? '使用中' : '已作废' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="170" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="success" link icon="View" @click="handleViewFile(scope.row)"> 查看 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button type="primary" @click="viewVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="DataCollectionForm" lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
import { extractList, getFileList } from '@/api/design/Professional';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
const total = ref(0);
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const professionalList = ref([]);
|
||||
const showSearch = ref(true);
|
||||
const loading = ref(false);
|
||||
const loadingFlie = ref(false);
|
||||
const viewVisible = ref(false); //文件列表展示
|
||||
const fileList = ref([]);
|
||||
const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
phone: undefined,
|
||||
status: undefined,
|
||||
params: {}
|
||||
}
|
||||
});
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const { queryParams } = toRefs(data);
|
||||
// 查询提资清单表
|
||||
const getList = async () => {
|
||||
let res = await extractList({ ...queryParams.value });
|
||||
if (res.code == 200) {
|
||||
professionalList.value = res.rows;
|
||||
total.value = res.total; //默认第一个
|
||||
}
|
||||
};
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/Professional/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'add'
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleViewInfo = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/Professional/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleUpdate = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/Professional/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleDownload = (row) => {
|
||||
// 导出接口
|
||||
proxy?.download(
|
||||
'design/extract/exportWord',
|
||||
{
|
||||
id: row.id
|
||||
},
|
||||
`互提资料.zip`
|
||||
);
|
||||
};
|
||||
const handleViewFile = (row) => {
|
||||
window.open(row.docUrl, '_blank');
|
||||
};
|
||||
const handleFile = async (row) => {
|
||||
// 查看文件
|
||||
viewVisible.value = true;
|
||||
loadingFlie.value = true;
|
||||
let res = await getFileList(row.id);
|
||||
if (res.code == 200) {
|
||||
fileList.value = res.data;
|
||||
}
|
||||
loadingFlie.value = false;
|
||||
};
|
||||
// 页面挂载时初始化数据
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.Professional {
|
||||
.el-tabs__header {
|
||||
height: 84vh !important;
|
||||
}
|
||||
}
|
||||
</style>
|
571
src/views/design/Professional/indexEdit.vue
Normal file
571
src/views/design/Professional/indexEdit.vue
Normal file
@ -0,0 +1,571 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">专业互提资料</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="appWidth mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
|
||||
<!-- 表单内容区域 -->
|
||||
<el-form :disabled="disableAll" ref="mainFormRef" :model="form" :rules="mainRules" label-width="120px" class="p-6">
|
||||
<!-- 基本信息区域 -->
|
||||
<div class="bg-blue-50 p-4 rounded-lg mb-6">
|
||||
<h3 class="text-lg font-semibold text-blue-700 mb-4">基本信息</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="提资人" prop="userId" class="mb-4">
|
||||
<el-select
|
||||
v-model="form.userId"
|
||||
placeholder="请选择提资人"
|
||||
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
|
||||
>
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业" prop="user_major" class="mb-4">
|
||||
<el-select
|
||||
v-model="form.user_major"
|
||||
placeholder="请选择专业"
|
||||
class="transition-all duration-300 border-gray-300"
|
||||
:rules="{ required: true, message: '请选择专业', trigger: 'change' }"
|
||||
>
|
||||
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" prop="phone" class="mb-4">
|
||||
<el-input placeholder="请输入电话" v-model="form.phone" autocomplete="off" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email" class="mb-4">
|
||||
<el-input placeholder="请输入邮箱" v-model="form.email" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 资料文件区域 -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-blue-700">资料文件清单</h3>
|
||||
<el-button type="primary" size="small" @click="addDocumentItem" icon="Plus"> 添加资料 </el-button>
|
||||
</div>
|
||||
<el-form :disabled="disableAll" ref="documentsFormRef" :model="form" class="space-y-4">
|
||||
<div
|
||||
v-for="(item, index) in form.documents"
|
||||
:key="item.id"
|
||||
class="bg-gray-50 p-4 rounded-lg transition-all duration-200 hover:shadow-sm"
|
||||
>
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<span class="text-sm font-medium text-gray-600">资料 {{ index + 1 }}</span>
|
||||
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
text-color="#ff4d4f"
|
||||
@click="removeDocumentItem(index)"
|
||||
icon="el-icon-delete"
|
||||
v-if="form.documents.length > 1"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item
|
||||
label="资料名称"
|
||||
:prop="`documents.${index}.catalogueName`"
|
||||
:rules="[{ required: true, message: '请输入文件资料名称', trigger: 'blur' }]"
|
||||
class="mb-4"
|
||||
>
|
||||
<el-select
|
||||
id="projectSelect"
|
||||
v-model="item.volumeCatalogId"
|
||||
placeholder="请选择资料"
|
||||
clearable
|
||||
filterable
|
||||
@change="handleSelect($event, item)"
|
||||
style="width: 150px; margin-right: 20px"
|
||||
>
|
||||
<el-option
|
||||
v-for="project in volumeCatalogList"
|
||||
:key="project.design"
|
||||
:label="project.documentName"
|
||||
:value="project.design"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" :prop="`documents.${index}.remark`" class="mb-4">
|
||||
<el-input placeholder="请输入备注" v-model="item.remark" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { systemUserList } from '@/api/design/appointment';
|
||||
import { extractBatch, extractDetail } from '@/api/design/Professional';
|
||||
import { listVolumeCatalog } from '@/api/design/volumeCatalog';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const disableAll = ref(false);
|
||||
const volumeCatalogList = ref([]);
|
||||
let volumeMap = new Map();
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_extract',
|
||||
label: '互提资料清单'
|
||||
}
|
||||
];
|
||||
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
// 用户列表
|
||||
const userList = ref([]);
|
||||
const userMap = new Map();
|
||||
// 表单引用
|
||||
const mainFormRef = ref();
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
projectId: currentProject.value?.id,
|
||||
userId: '', // 收资人
|
||||
user_major: '', // 专业
|
||||
phone: '', // 电话
|
||||
email: '', // 邮箱
|
||||
id: '',
|
||||
status: '',
|
||||
documents: [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '', // 卷册目录名称
|
||||
remark: '', // 备注
|
||||
volumeCatalogId: '' //卷册目录ID
|
||||
}
|
||||
] as Array<{
|
||||
id: number;
|
||||
catalogueName: string;
|
||||
remark: string;
|
||||
volumeCatalogId: string;
|
||||
}>
|
||||
});
|
||||
// 主表单验证规则
|
||||
const mainRules = reactive({
|
||||
userId: [{ required: true, message: '请输入收资人', trigger: 'blur' }],
|
||||
user_major: [{ required: true, message: '请选择专业', trigger: 'change' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
|
||||
]
|
||||
});
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
if (mainFormRef.value) {
|
||||
mainFormRef.value.resetFields();
|
||||
}
|
||||
// 重置资料列表,保留一个空项
|
||||
form.documents = [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: '',
|
||||
volumeCatalogId: ''
|
||||
}
|
||||
];
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
// 添加资料项
|
||||
const addDocumentItem = () => {
|
||||
form.documents.push({
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: '',
|
||||
volumeCatalogId: ''
|
||||
});
|
||||
};
|
||||
|
||||
// 删除资料项
|
||||
const removeDocumentItem = (index: number) => {
|
||||
form.documents.splice(index, 1);
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
buttonLoading.value = true;
|
||||
dialog.visible = false;
|
||||
// 验证表单数据
|
||||
mainFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
console.log('验证成功');
|
||||
form.documents.map((item, i) => {
|
||||
item.num = i + 1;
|
||||
});
|
||||
let body = {
|
||||
desExtractBo: {
|
||||
projectId: currentProject.value?.id,
|
||||
userId: form.userId, // 收资人
|
||||
userMajor: form.user_major, // 专业
|
||||
id: form.id,
|
||||
phone: form.phone, // 电话
|
||||
email: form.email, // 邮箱
|
||||
userName: userMap.get(form.userId)
|
||||
},
|
||||
catalogueList: form.documents
|
||||
};
|
||||
let res = await extractBatch(body);
|
||||
if (res.code == 200) {
|
||||
buttonLoading.value = false;
|
||||
dialog.visible = false;
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
// 表单验证通过,执行提交逻辑
|
||||
form.id = res.data;
|
||||
submit(status.value, form);
|
||||
} else {
|
||||
// 表单验证失败,提示用户并关闭加载状态
|
||||
proxy?.$modal.msgError('请完善必填信息后再提交');
|
||||
buttonLoading.value = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
const submit = async (status, data) => {
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
/** 查询当前部门的所有用户 */
|
||||
const getDeptAllUser = async (deptId: any) => {
|
||||
try {
|
||||
const res = await systemUserList({ deptId });
|
||||
// 实际项目中使用接口返回的数据
|
||||
userList.value = res.rows;
|
||||
userList.value.forEach((user) => {
|
||||
userMap.set(user.userId, user.nickName);
|
||||
});
|
||||
} catch (error) {
|
||||
ElMessage.error('获取用户列表失败');
|
||||
}
|
||||
};
|
||||
// 查询数据 再次回显
|
||||
const byProjectIdAll = async () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
// 调用接口获取数据
|
||||
const res = await extractDetail(routeParams.value.id);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data;
|
||||
// 回显基本信息
|
||||
form.userId = data.userId || '';
|
||||
form.user_major = data.userMajor || '';
|
||||
form.phone = data.phone || '';
|
||||
form.email = data.email || '';
|
||||
form.id = data.id || '';
|
||||
form.status = data.status || '';
|
||||
if (data.status != 'draft') {
|
||||
disableAll.value = true;
|
||||
}
|
||||
|
||||
// 回显资料文件列表
|
||||
if (data.catalogueList && data.catalogueList.length > 0) {
|
||||
// 清空现有列表
|
||||
form.documents = [];
|
||||
// 填充新数据
|
||||
data.catalogueList.forEach((item: any, index: number) => {
|
||||
form.documents.push({
|
||||
id: item.id || Date.now() + index, // 确保id唯一
|
||||
catalogueName: item.catalogueName || '',
|
||||
remark: item.remark || '',
|
||||
volumeCatalogId: item.volumeCatalogId
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 如果没有资料,保持一个空项
|
||||
form.documents = [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: '',
|
||||
volumeCatalogId: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
/** 查询卷册目录列表 */
|
||||
const getList = async () => {
|
||||
const res = await listVolumeCatalog({ projectId: currentProject.value?.id, auditStatus: 'finish' });
|
||||
volumeCatalogList.value = res.rows;
|
||||
volumeCatalogList.value.forEach((e) => {
|
||||
volumeMap.set(e.design, e);
|
||||
});
|
||||
};
|
||||
const handleSelect = (val, item) => {
|
||||
item.catalogueName = volumeMap.get(val).documentName;
|
||||
};
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
getList(); // 获取卷册目录
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getDeptAllUser(userStore.deptId).then(() => {
|
||||
byProjectIdAll();
|
||||
});
|
||||
} else {
|
||||
getDeptAllUser(userStore.deptId);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
805
src/views/design/appointment/index.vue
Normal file
805
src/views/design/appointment/index.vue
Normal file
@ -0,0 +1,805 @@
|
||||
<template>
|
||||
<div class="p-6 bg-gray-50">
|
||||
<div class="appWidth mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
|
||||
<!-- 表单标题区域 -->
|
||||
<div class="bg-gradient-to-r from-blue-500 to-blue-600 text-white p-6">
|
||||
<h2 class="text-2xl font-bold flex items-center"><i class="el-icon-user-circle mr-3"></i>人员配置</h2>
|
||||
<p class="text-blue-100 mt-2 opacity-90">请配置项目相关负责人员信息</p>
|
||||
<el-button @click="disabledForm = false" class="px-8 py-2.5 transition-all duration-300 font-medium" v-if="disabledForm">
|
||||
点击编辑
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- 表单内容区域 -->
|
||||
<el-form ref="leaveFormRef" :model="form" :disabled="disabledForm" :rules="rules" label-width="120px" class="p-6 space-y-6">
|
||||
<!-- 设计负责人 -->
|
||||
<div class="fonts">
|
||||
<el-row>
|
||||
<el-col :span="8"
|
||||
><el-form-item label="设计负责人" prop="designLeader" class="mb-4">
|
||||
<el-select
|
||||
v-model="form.designLeader"
|
||||
placeholder="请选择设计负责人"
|
||||
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
|
||||
>
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 专业人员配置:专业 + 设计人员 + 校审人员 横向排列 -->
|
||||
<div class="border border-gray-200 rounded-lg p-5 transition-all duration-300 hover:shadow-md bg-gray-50">
|
||||
<div class="flex justify-between items-center mb-5">
|
||||
<h3 class="text-lg font-semibold text-gray-700 flex items-center"><i class="el-icon-users mr-2 text-blue-500"></i>专业人员配置</h3>
|
||||
<div class="flex gap-3">
|
||||
<!-- 新增专业按钮 -->
|
||||
<el-button type="primary" size="small" :disabled="disabledForm" @click="addMajor">
|
||||
<i class="el-icon-plus mr-1"></i>新增专业
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表头 -->
|
||||
<el-row :gutter="20" class="mb-3 font-medium text-gray-700">
|
||||
<el-col :span="6" :xs="24" :sm="8">专业</el-col>
|
||||
<el-col :span="9" :xs="24" :sm="8">设计人员(可多选)</el-col>
|
||||
<el-col :span="9" :xs="24" :sm="8">校审人员(可多选)</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<el-divider class="my-4" />
|
||||
|
||||
<!-- 专业配置行:专业(左)+ 设计人员(中)+ 校审人员(右) 横向排列 -->
|
||||
<div
|
||||
v-for="(majorConfig, configIndex) in combinedConfigs"
|
||||
:key="configIndex"
|
||||
style="background: aliceblue; border-radius: 10px"
|
||||
class="mb-5 animate-fadeIn"
|
||||
>
|
||||
<el-row :gutter="20" class="items-top">
|
||||
<!-- 左侧:专业选择 -->
|
||||
<el-col :span="6" :xs="24" :sm="8" class="mb-4 sm:mb-0" style="margin-top: 8px">
|
||||
<el-form-item
|
||||
:prop="`designers.${configIndex}.userMajor`"
|
||||
:rules="{ required: true, message: '请选择专业', trigger: 'change' }"
|
||||
class="mb-0"
|
||||
label-width="80px"
|
||||
label="专业"
|
||||
>
|
||||
<!-- 专业选择下拉框 -->
|
||||
<el-select
|
||||
v-model="form.designers[configIndex].userMajor"
|
||||
placeholder="请选择专业"
|
||||
class="w-full transition-all duration-300 border-gray-300"
|
||||
@change="(val) => handleMajorChange(val, configIndex)"
|
||||
>
|
||||
<!-- 临时添加调试显示 -->
|
||||
<template v-if="des_user_major && des_user_major.length > 0">
|
||||
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-option label="无专业数据" value="" disabled />
|
||||
</template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 中间:设计人员 -->
|
||||
<el-col :span="9" :xs="24" :sm="8" class="mb-4 sm:mb-0">
|
||||
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-blue-200 py-0 sm:py-2">
|
||||
<!-- 设计人员列表 -->
|
||||
<div class="space-y-3">
|
||||
<div v-for="(person, personIndex) in majorConfig.designPersons" :key="personIndex" class="flex items-center">
|
||||
<el-form-item
|
||||
:prop="`designers.${configIndex}.persons.${personIndex}.userId`"
|
||||
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
|
||||
class="flex-1 mr-3 mb-0"
|
||||
label="设计人员"
|
||||
label-width="80px"
|
||||
>
|
||||
<el-select
|
||||
v-model="person.userId"
|
||||
placeholder="请选择设计人员"
|
||||
class="w-full transition-all duration-300 border-gray-300"
|
||||
@change="() => checkDuplicate(person, 'designers', configIndex, personIndex)"
|
||||
>
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="removePerson('designers', configIndex, personIndex)"
|
||||
class="transition-all duration-300 hover:bg-red-600"
|
||||
:disabled="majorConfig.designPersons.length <= 1 || disabledForm"
|
||||
>
|
||||
<el-icon :size="16">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
size="small"
|
||||
@click="addPerson('designers', configIndex)"
|
||||
class="transition-all duration-300 transform hover:scale-105"
|
||||
:disabled="!majorConfig.userMajor || disabledForm"
|
||||
>
|
||||
<el-icon :size="16">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<div
|
||||
v-if="majorConfig.designPersons.length == 0"
|
||||
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
|
||||
>
|
||||
暂无设计人员,请点击"添加设计人员"
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧:校审人员 -->
|
||||
<el-col :span="9" :xs="24" :sm="8">
|
||||
<div class="pl-0 sm:pl-4 border-l-0 sm:border-l-2 border-green-200 py-0 sm:py-2">
|
||||
<!-- 校审人员列表 -->
|
||||
<div class="space-y-3">
|
||||
<div v-for="(person, personIndex) in majorConfig.reviewPersons" :key="personIndex" class="flex items-center">
|
||||
<el-form-item
|
||||
:prop="`reviewers.${configIndex}.persons.${personIndex}.userId`"
|
||||
:rules="{ required: true, message: '请选择人员', trigger: 'change' }"
|
||||
class="flex-1 mr-3 mb-0"
|
||||
label="校审人员"
|
||||
label-width="80px"
|
||||
>
|
||||
<el-select
|
||||
v-model="person.userId"
|
||||
placeholder="请选择校审人员"
|
||||
class="w-full transition-all duration-300 border-gray-300"
|
||||
@change="() => checkDuplicate(person, 'reviewers', configIndex, personIndex)"
|
||||
>
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="removePerson('reviewers', configIndex, personIndex)"
|
||||
class="transition-all duration-300 hover:bg-red-600"
|
||||
:disabled="majorConfig.reviewPersons.length <= 1 || disabledForm"
|
||||
>
|
||||
<el-icon :size="16">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
size="small"
|
||||
@click="addPerson('reviewers', configIndex)"
|
||||
class="transition-all duration-300 transform hover:scale-105"
|
||||
:disabled="!majorConfig.userMajor || disabledForm"
|
||||
>
|
||||
<el-icon :size="16">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<div
|
||||
v-if="majorConfig.reviewPersons.length == 0"
|
||||
class="text-gray-500 text-sm py-2 bg-gray-100 rounded-lg border border-dashed border-gray-200 mt-1"
|
||||
>
|
||||
暂无校审人员,请点击"添加校审人员"
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 删除专业配置行 -->
|
||||
<el-row class="mt-2">
|
||||
<el-col :span="24" class="text-right pr-4">
|
||||
<el-button
|
||||
type="text"
|
||||
class="text-red-500 hover:text-red-700 transition-colors"
|
||||
@click="removeMajor(configIndex)"
|
||||
:disabled="combinedConfigs.length <= 1 || disabledForm"
|
||||
>
|
||||
<i class="el-icon-delete mr-1"></i>删除专业
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提交按钮区域 -->
|
||||
<div class="flex justify-center space-x-6 mt-8 pt-6 border-t border-gray-100">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
v-hasPermi="['design:user:batch']"
|
||||
@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"
|
||||
:disabled="disabledForm"
|
||||
>
|
||||
<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"
|
||||
:disabled="disabledForm"
|
||||
>
|
||||
<i class="el-icon-refresh mr-2"></i>重置
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="PersonnelForm" lang="ts">
|
||||
import { ref, reactive, computed, onMounted, toRefs, watch, WatchStopHandle } from 'vue';
|
||||
import { getCurrentInstance } from 'vue';
|
||||
import type { ComponentInternalInstance } from 'vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { ElMessage, ElLoading } from 'element-plus';
|
||||
import { Delete, Plus } from '@element-plus/icons-vue'; // 修复:添加Plus图标导入
|
||||
import { designUserAdd, designUserList, systemUserList } from '@/api/design/appointment';
|
||||
|
||||
// 获取当前实例
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
// 专业字典数据 - 增加默认空数组避免undefined
|
||||
const { des_user_major = ref([]) } = toRefs<any>(proxy?.useDict('des_user_major') || {});
|
||||
|
||||
// 调试:打印专业数据
|
||||
onMounted(() => {
|
||||
console.log('专业数据:', des_user_major.value);
|
||||
});
|
||||
|
||||
// 表单数据:保持原有数据结构不变
|
||||
interface MajorGroup {
|
||||
userMajor: string | null; // 专业
|
||||
persons: Array<{ userId: number | null }>; // 该专业下的多个人员
|
||||
}
|
||||
const form = reactive({
|
||||
projectId: currentProject.value?.id,
|
||||
designLeader: null, // 设计负责人
|
||||
designers: [] as MajorGroup[], // 设计人员:按专业分组,每组含多个人员
|
||||
reviewers: [] as MajorGroup[] // 校审人员:按专业分组,每组含多个人员
|
||||
});
|
||||
|
||||
// 组合配置用于视图展示(专业+设计人员+校审人员)
|
||||
const combinedConfigs = computed(() => {
|
||||
// 确保designers和reviewers数组长度一致
|
||||
const maxLength = Math.max(form.designers.length, form.reviewers.length);
|
||||
while (form.designers.length < maxLength) {
|
||||
form.designers.push(createEmptyMajorGroup());
|
||||
}
|
||||
while (form.reviewers.length < maxLength) {
|
||||
form.reviewers.push(createEmptyMajorGroup());
|
||||
}
|
||||
|
||||
// 组合数据用于视图展示
|
||||
return form.designers.map((designerGroup, index) => ({
|
||||
userMajor: designerGroup.userMajor,
|
||||
designPersons: designerGroup.persons,
|
||||
reviewPersons: form.reviewers[index].persons
|
||||
}));
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
designLeader: [{ required: true, message: '请选择设计负责人', trigger: 'change' }]
|
||||
});
|
||||
|
||||
// 用户列表
|
||||
const userList = ref([]);
|
||||
|
||||
// 表单引用
|
||||
const leaveFormRef = ref();
|
||||
const disabledForm = ref(false); //控制提交按钮状态
|
||||
|
||||
/** 查询当前部门的所有用户 */
|
||||
const getDeptAllUser = async (deptId: any) => {
|
||||
try {
|
||||
const res = await systemUserList({ deptId });
|
||||
userList.value = res.rows;
|
||||
} catch (error) {
|
||||
ElMessage.error('获取用户列表失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 查询当前表单数据并回显 */
|
||||
const designUser = async () => {
|
||||
if (!currentProject.value?.id) return;
|
||||
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '加载配置数据中...',
|
||||
background: 'rgba(255, 255, 255, 0.7)'
|
||||
});
|
||||
try {
|
||||
const res = await designUserList({ projectId: currentProject.value?.id });
|
||||
// 清空现有数据
|
||||
form.designLeader = null;
|
||||
form.designers = [];
|
||||
form.reviewers = [];
|
||||
|
||||
if (res.code == 200 && res.rows && res.rows.length > 0) {
|
||||
disabledForm.value = true;
|
||||
// 1. 分类整理数据(按用户类型)
|
||||
const designLeader = res.rows.find((item) => item.userType == 1);
|
||||
const designerItems = res.rows.filter((item) => item.userType == 2);
|
||||
const reviewerItems = res.rows.filter((item) => item.userType == 3);
|
||||
|
||||
// 2. 回显设计负责人
|
||||
if (designLeader) form.designLeader = designLeader.userId;
|
||||
|
||||
// 3. 回显设计人员(按专业分组)
|
||||
form.designers = groupPersonByMajor(designerItems);
|
||||
// 4. 回显校审人员(按专业分组)
|
||||
form.reviewers = groupPersonByMajor(reviewerItems);
|
||||
}
|
||||
|
||||
// 补全默认空项(至少1个专业分组,每组至少1个人员)
|
||||
if (form.designers.length == 0) form.designers.push(createEmptyMajorGroup());
|
||||
if (form.reviewers.length == 0) form.reviewers.push(createEmptyMajorGroup());
|
||||
} catch (error) {
|
||||
ElMessage.error('获取配置数据失败');
|
||||
// 异常时初始化默认空项
|
||||
form.designers = [createEmptyMajorGroup()];
|
||||
form.reviewers = [createEmptyMajorGroup()];
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
};
|
||||
|
||||
/** 辅助函数:创建空的专业分组(含1个空人员) */
|
||||
const createEmptyMajorGroup = (): MajorGroup => ({
|
||||
userMajor: null,
|
||||
persons: [{ userId: null }]
|
||||
});
|
||||
|
||||
/** 辅助函数:按专业分组整理人员数据(用于回显) */
|
||||
const groupPersonByMajor = (items: any[]): MajorGroup[] => {
|
||||
const groupMap: Record<string, MajorGroup> = {};
|
||||
items.forEach((item) => {
|
||||
const major = item.userMajor || '未分类';
|
||||
// 不存在该专业分组则创建
|
||||
if (!groupMap[major]) {
|
||||
groupMap[major] = { userMajor: item.userMajor, persons: [] };
|
||||
}
|
||||
// 添加当前人员到专业分组
|
||||
groupMap[major].persons.push({ userId: item.userId });
|
||||
});
|
||||
// 处理空分组(确保每组至少1个人员)
|
||||
Object.values(groupMap).forEach((group) => {
|
||||
if (group.persons.length == 0) group.persons.push({ userId: null });
|
||||
});
|
||||
return Object.values(groupMap);
|
||||
};
|
||||
|
||||
/** 新增专业配置行 */
|
||||
const addMajor = () => {
|
||||
form.designers.push(createEmptyMajorGroup());
|
||||
form.reviewers.push(createEmptyMajorGroup());
|
||||
|
||||
// 滚动到新增的专业配置行
|
||||
setTimeout(() => {
|
||||
const groups = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .animate-fadeIn`);
|
||||
if (groups.length > 0) {
|
||||
groups[groups.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
/** 删除专业配置行 */
|
||||
const removeMajor = (configIndex: number) => {
|
||||
if (form.designers.length <= 1) {
|
||||
ElMessage.warning('至少保留一个专业配置');
|
||||
return;
|
||||
}
|
||||
form.designers.splice(configIndex, 1);
|
||||
form.reviewers.splice(configIndex, 1);
|
||||
};
|
||||
|
||||
/** 给指定专业配置行添加人员 */
|
||||
const addPerson = (type: 'designers' | 'reviewers', configIndex: number) => {
|
||||
form[type][configIndex].persons.push({ userId: null });
|
||||
|
||||
// 滚动到新增的人员选择框
|
||||
setTimeout(() => {
|
||||
const personSelects = document.querySelectorAll(`[data-v-${proxy?.$options.__scopeId}] .el-select`);
|
||||
if (personSelects.length > 0) {
|
||||
personSelects[personSelects.length - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
/** 从指定专业配置行删除人员 */
|
||||
const removePerson = (type: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
|
||||
const targetGroup = form[type][configIndex];
|
||||
if (targetGroup.persons.length <= 1) {
|
||||
ElMessage.warning(`该专业至少保留一个${type == 'designers' ? '设计' : '校审'}人员`);
|
||||
return;
|
||||
}
|
||||
targetGroup.persons.splice(personIndex, 1);
|
||||
};
|
||||
|
||||
/** 专业变更时:清空当前专业下的人员(避免专业与人员不匹配) */
|
||||
const handleMajorChange = (newMajor: string, configIndex: number) => {
|
||||
// 直接修改原始数据源,确保响应式生效
|
||||
form.designers[configIndex].userMajor = newMajor;
|
||||
form.reviewers[configIndex].userMajor = newMajor;
|
||||
form.designers[configIndex].persons = [{ userId: null }];
|
||||
form.reviewers[configIndex].persons = [{ userId: null }];
|
||||
// ElMessage.info(`已重置「${getMajorLabel(newMajor)}」专业下的人员,请重新选择`);
|
||||
};
|
||||
|
||||
// ========== 核心:重复校验逻辑 ==========
|
||||
/**
|
||||
* 校验同一角色内(设计/校审)的「专业+人员」组合唯一性
|
||||
*/
|
||||
const checkDuplicate = (current: { userId: number | null }, role: 'designers' | 'reviewers', configIndex: number, personIndex: number) => {
|
||||
console.log(`校验触发 - 角色: ${role}, 专业索引: ${configIndex}, 人员索引: ${personIndex}, 人员ID: ${current.userId}`);
|
||||
console.log(form);
|
||||
|
||||
const currentGroup = form[role][configIndex];
|
||||
// 未选专业/人员时不校验
|
||||
if (!currentGroup.userMajor || !current.userId) return;
|
||||
|
||||
// 生成当前「专业+人员」唯一标识
|
||||
const currentKey = `${currentGroup.userMajor}-${current.userId}`;
|
||||
let duplicateItem = null;
|
||||
|
||||
// 1. 检查当前专业配置行内是否有重复人员
|
||||
duplicateItem = currentGroup.persons.find((item, idx) => {
|
||||
return idx !== personIndex && item.userId == current.userId;
|
||||
});
|
||||
if (duplicateItem) {
|
||||
ElMessage.warning(`当前专业下「${getUserName(current.userId)}」已存在,请重新选择`);
|
||||
current.userId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 检查同一角色内其他专业配置行是否有重复(专业+人员唯一)
|
||||
form[role].forEach((group, gIdx) => {
|
||||
if (gIdx == configIndex) return; // 跳过当前配置行
|
||||
group.persons.forEach((item) => {
|
||||
if (`${group.userMajor}-${item.userId}` == currentKey) {
|
||||
duplicateItem = item;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (duplicateItem) {
|
||||
ElMessage.warning(`「${getMajorLabel(currentGroup.userMajor)}+${getUserName(current.userId)}」组合已存在,请重新选择`);
|
||||
current.userId = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** 辅助函数:通过专业值获取专业名称 */
|
||||
const getMajorLabel = (majorValue: string | null) => {
|
||||
if (!majorValue || !des_user_major.value) return '';
|
||||
const major = des_user_major.value.find((item: any) => item.value == majorValue);
|
||||
return major ? major.label : majorValue;
|
||||
};
|
||||
|
||||
/** 辅助函数:通过用户ID获取用户名 */
|
||||
const getUserName = (userId: number | null) => {
|
||||
if (!userId || !userList.value.length) return '';
|
||||
const user = userList.value.find((item: any) => item.userId == userId);
|
||||
return user ? user.nickName : userId;
|
||||
};
|
||||
|
||||
/** 提交表单(保持原有数据结构) */
|
||||
const submitForm = async () => {
|
||||
if (!leaveFormRef.value) return;
|
||||
try {
|
||||
// 1. 基础表单验证
|
||||
await leaveFormRef.value.validate();
|
||||
|
||||
// 2. 提交前二次校验:「专业+人员」组合唯一性
|
||||
let hasDuplicate = false;
|
||||
const allKeys: string[] = [];
|
||||
|
||||
// 收集所有「专业+人员」组合(设计+校审分开校验)
|
||||
const collectKeys = (roleGroups: MajorGroup[], roleName: string) => {
|
||||
roleGroups.forEach((group) => {
|
||||
if (!group.userMajor) return;
|
||||
group.persons.forEach((person) => {
|
||||
if (!person.userId) return;
|
||||
const key = `${group.userMajor}-${person.userId}`;
|
||||
if (allKeys.includes(key)) {
|
||||
hasDuplicate = true;
|
||||
ElMessage.error(`${roleName}中存在重复的「专业+人员」组合,请检查`);
|
||||
}
|
||||
allKeys.push(key);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 校验设计人员
|
||||
collectKeys(form.designers, '设计人员');
|
||||
if (hasDuplicate) return;
|
||||
|
||||
// 清空临时数组,校验校审人员(不校验设计与校审之间)
|
||||
allKeys.length = 0;
|
||||
collectKeys(form.reviewers, '校审人员');
|
||||
if (hasDuplicate) return;
|
||||
|
||||
// 3. 构建提交数据(适配后端原有数据格式)
|
||||
const submitData = {
|
||||
projectId: form.projectId,
|
||||
personnel: [
|
||||
// 设计负责人
|
||||
{
|
||||
userId: form.designLeader,
|
||||
userType: 'designLeader',
|
||||
userMajor: null
|
||||
},
|
||||
// 设计人员:展开专业分组,每个人员单独作为一条数据
|
||||
...form.designers.flatMap((group) =>
|
||||
group.persons.map((person) => ({
|
||||
userId: person.userId,
|
||||
userType: 'designer',
|
||||
userMajor: group.userMajor
|
||||
}))
|
||||
),
|
||||
// 校审人员:展开专业分组,每个人员单独作为一条数据
|
||||
...form.reviewers.flatMap((group) =>
|
||||
group.persons.map((person) => ({
|
||||
userId: person.userId,
|
||||
userType: 'reviewer',
|
||||
userMajor: group.userMajor
|
||||
}))
|
||||
)
|
||||
]
|
||||
};
|
||||
|
||||
// 4. 数据处理(保持原有逻辑不变)
|
||||
const arr = [];
|
||||
userList.value.forEach((item) => {
|
||||
submitData.personnel.forEach((item1) => {
|
||||
if (item1.userId == item.userId) {
|
||||
let userType = 1;
|
||||
if (item1.userType == 'designer') userType = 2;
|
||||
else if (item1.userType == 'reviewer') userType = 3;
|
||||
arr.push({
|
||||
userName: item.nickName,
|
||||
projectId: submitData.projectId,
|
||||
userId: item1.userId,
|
||||
userType: userType,
|
||||
userMajor: item1.userMajor
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 5. 提交到后端(保持原有逻辑不变)
|
||||
const loading = ElLoading.service({ text: '提交中...', background: 'rgba(255,255,255,0.7)' });
|
||||
const res = await designUserAdd({
|
||||
list: arr,
|
||||
projectId: currentProject.value?.id
|
||||
});
|
||||
if (res.code == 200) {
|
||||
disabledForm.value = true;
|
||||
ElMessage.success('提交成功');
|
||||
} else {
|
||||
ElMessage.error(res.msg || '提交失败');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('请完善表单信息后再提交');
|
||||
} finally {
|
||||
ElLoading.service().close();
|
||||
}
|
||||
};
|
||||
|
||||
/** 重置表单(适配新数据结构) */
|
||||
const resetForm = () => {
|
||||
if (leaveFormRef.value) {
|
||||
leaveFormRef.value.resetFields();
|
||||
// 重置为默认空状态(1个专业分组,每组1个空人员)
|
||||
form.designers = [createEmptyMajorGroup()];
|
||||
form.reviewers = [createEmptyMajorGroup()];
|
||||
ElMessage.info('表单已重置');
|
||||
}
|
||||
};
|
||||
|
||||
// 监听项目ID刷新数据
|
||||
const listeningProject: WatchStopHandle = watch(
|
||||
() => currentProject.value?.id,
|
||||
() => {
|
||||
getDeptAllUser(userStore.deptId).then(() => {
|
||||
designUser();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 页面生命周期
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
onMounted(() => {
|
||||
getDeptAllUser(userStore.deptId).then(() => {
|
||||
designUser();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.appWidth {
|
||||
width: 70vw;
|
||||
max-width: 1600px;
|
||||
|
||||
.el-select__wrapper {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.el-button--small {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.fonts {
|
||||
.el-form-item--default .el-form-item__label {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义动画
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fadeIn {
|
||||
animation: fadeIn 0.3s ease-out forwards;
|
||||
}
|
||||
|
||||
// 表单样式优化
|
||||
::v-deep .el-form {
|
||||
--el-form-item-margin-bottom: 0;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 0;
|
||||
|
||||
&__label {
|
||||
font-weight: 500;
|
||||
color: #4e5969;
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-select {
|
||||
width: 100%;
|
||||
|
||||
.el-input__inner {
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
&:hover .el-input__inner {
|
||||
border-color: #66b1ff;
|
||||
}
|
||||
|
||||
&.el-select-focus .el-input__inner {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-button {
|
||||
border-radius: 6px;
|
||||
padding: 8px 16px;
|
||||
|
||||
&--primary {
|
||||
background-color: #409eff;
|
||||
border-color: #409eff;
|
||||
|
||||
&:hover {
|
||||
background-color: #66b1ff;
|
||||
border-color: #66b1ff;
|
||||
}
|
||||
}
|
||||
|
||||
&--success {
|
||||
background-color: #67c23a;
|
||||
border-color: #67c23a;
|
||||
|
||||
&:hover {
|
||||
background-color: #85ce61;
|
||||
border-color: #85ce61;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #b3e099;
|
||||
border-color: #b3e099;
|
||||
}
|
||||
}
|
||||
|
||||
&--danger {
|
||||
background-color: #f56c6c;
|
||||
border-color: #f56c6c;
|
||||
|
||||
&:hover {
|
||||
background-color: #f78989;
|
||||
border-color: #f78989;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #ffcccc;
|
||||
border-color: #ffbbbb;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&--text {
|
||||
color: #f56c6c;
|
||||
|
||||
&:hover {
|
||||
color: #f78989;
|
||||
background-color: rgba(245, 108, 108, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式网格布局
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.grid-cols-1 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.md\:grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
// 适配小屏幕(小于768px时,垂直排列)
|
||||
@media (max-width: 768px) {
|
||||
.appWidth {
|
||||
width: 95vw;
|
||||
}
|
||||
|
||||
::v-deep .el-form {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item__label {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
// 小屏幕下各列上下间距
|
||||
::v-deep .el-col-xs-24 + .el-col-xs-24 {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
342
src/views/design/billofQuantities/index.vue
Normal file
342
src/views/design/billofQuantities/index.vue
Normal file
@ -0,0 +1,342 @@
|
||||
<template>
|
||||
<div class="billof-quantities">
|
||||
<!-- tabPosition="left" -->
|
||||
<el-tabs type="border-card" @tab-change="handleTabChange">
|
||||
<el-tab-pane v-for="(item, index) in work_order_type" :key="item.value" :label="item.label">
|
||||
<el-card v-if="index < 3" shadow="always">
|
||||
<el-form :model="state.queryForm" :inline="true">
|
||||
<el-form-item label="版本号" prop="versions">
|
||||
<el-select v-model="state.queryForm.versions" placeholder="选择版本号">
|
||||
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="表名" prop="sheet">
|
||||
<el-select v-model="state.queryForm.sheet" placeholder="选择表名" @change="handleChange">
|
||||
<el-option v-for="item in state.sheets" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="openTable(true, index)">一键展开</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="openTable(false, index)">一键收起</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel" :show-file-list="false">
|
||||
<template #trigger>
|
||||
<el-button type="primary">导入excel</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-card v-if="index == 3" shadow="always">
|
||||
<el-form :model="state.queryForm" :inline="true">
|
||||
<el-form-item label="版本号" prop="versions">
|
||||
<el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion">
|
||||
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
class="upload-demo"
|
||||
:http-request="importExcel"
|
||||
style="margin-right: 12px"
|
||||
v-if="Object.keys(state.versionsData).length === 0 || state.versionsData.status == 'cancel'"
|
||||
:show-file-list="false"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary">导入excel</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-button v-if="state.versionsData.status == 'draft'" type="primary" con="edit" @click="clickApprovalSheet()">审核</el-button>
|
||||
<el-button
|
||||
v-if="state.versionsData.status == 'waiting' || state.versionsData.status == 'finish'"
|
||||
icon="view"
|
||||
@click="lookApprovalFlow()"
|
||||
type="warning"
|
||||
>查看流程</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-table
|
||||
v-if="index < 3"
|
||||
:ref="(el) => (tableRef[index] = el)"
|
||||
:data="state.tableData"
|
||||
v-loading="state.loading.list"
|
||||
stripe
|
||||
:row-class-name="state.tableData.length === 0 ? 'table-null' : ''"
|
||||
style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)"
|
||||
row-key="id"
|
||||
lazy
|
||||
border
|
||||
:default-expand-all="true"
|
||||
>
|
||||
<el-table-column prop="num" label="编号" />
|
||||
<el-table-column prop="name" label="工程或费用名称" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
</el-table>
|
||||
<el-table v-if="index == 3" :data="state.tableData" style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" border>
|
||||
<el-table-column prop="num" label="编号" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="specification" label="规格" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="billofQuantities">
|
||||
import { ref, reactive, onMounted, computed, toRefs, getCurrentInstance, nextTick } from 'vue';
|
||||
import {
|
||||
obtainAllVersionNumbers,
|
||||
importExcelFile,
|
||||
obtainTheList,
|
||||
sheetList,
|
||||
detailsMaterialAndEquipmentApproval
|
||||
} from '@/api/design/billofQuantities/index';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { work_order_type } = toRefs(proxy?.useDict('work_order_type'));
|
||||
const tableRef = ref({});
|
||||
console.log(currentProject.value);
|
||||
|
||||
// tableData
|
||||
// 版本号
|
||||
const state = reactive({
|
||||
work_order_type: 0,
|
||||
// 版本号
|
||||
version_num: '',
|
||||
options: [], // 版本号选项
|
||||
sheets: [], // sheet选项
|
||||
queryForm: {
|
||||
projectId: currentProject.value?.id,
|
||||
versions: '',
|
||||
sheet: '',
|
||||
pageSize: 20,
|
||||
pageNum: 1
|
||||
},
|
||||
loading: {
|
||||
versions: false,
|
||||
sheets: false,
|
||||
list: false
|
||||
},
|
||||
error: null,
|
||||
// 前三个
|
||||
tableData: [],
|
||||
// 版本号
|
||||
versionsData: {}
|
||||
});
|
||||
// tab切换
|
||||
const handleTabChange = (tab) => {
|
||||
state.tableData = [];
|
||||
state.options = [];
|
||||
state.sheets = [];
|
||||
state.queryForm.sheet = '';
|
||||
state.queryForm.versions = '';
|
||||
state.work_order_type = tab;
|
||||
if (tab <= 2) {
|
||||
getVersionNums();
|
||||
} else {
|
||||
getVersionNums(false);
|
||||
}
|
||||
};
|
||||
onMounted(async () => {
|
||||
await getVersionNums();
|
||||
});
|
||||
// 获取版本号
|
||||
async function getVersionNums(isSheet = true) {
|
||||
try {
|
||||
state.loading.versions = true;
|
||||
state.error = null;
|
||||
|
||||
const res = await obtainAllVersionNumbers({
|
||||
projectId: currentProject.value?.id,
|
||||
workOrderType: state.work_order_type,
|
||||
pageSize: 1000,
|
||||
pageNum: 1
|
||||
});
|
||||
|
||||
const { code, rows } = res || {};
|
||||
if (code === 200) {
|
||||
state.options = rows || [];
|
||||
if (state.options.length > 0) {
|
||||
state.queryForm.versions = state.options[0].versions;
|
||||
if (state.work_order_type == 3) {
|
||||
state.versionsData = state.options[0] || [];
|
||||
console.log('state.versionsData', state.versionsData);
|
||||
}
|
||||
// 等待表名加载完成
|
||||
console.log(isSheet, state.sheets.length);
|
||||
if (isSheet) {
|
||||
await handleSheetName();
|
||||
} else {
|
||||
await handleQueryList(isSheet);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await handleQueryList(isSheet);
|
||||
}
|
||||
} catch (err) {
|
||||
state.error = `获取版本号时发生错误: ${err.message}`;
|
||||
console.error(state.error, err);
|
||||
} finally {
|
||||
state.loading.versions = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表名
|
||||
async function handleSheetName() {
|
||||
if (!state.queryForm.versions) {
|
||||
console.warn('版本号不存在,无法获取表名');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
state.loading.sheets = true;
|
||||
state.error = null;
|
||||
|
||||
const { data } = await sheetList({
|
||||
projectId: currentProject.value?.id,
|
||||
workOrderType: state.work_order_type,
|
||||
versions: state.queryForm.versions
|
||||
});
|
||||
|
||||
state.sheets = data || [];
|
||||
if (state.sheets.length > 0) {
|
||||
state.queryForm.sheet = state.sheets[0];
|
||||
}
|
||||
|
||||
// 获取列表数据
|
||||
await handleQueryList();
|
||||
} catch (err) {
|
||||
state.error = `获取表名时发生错误: ${err.message}`;
|
||||
console.error(state.error, err);
|
||||
} finally {
|
||||
state.loading.sheets = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取列表
|
||||
async function handleQueryList(isSheet = true) {
|
||||
if (isSheet && !state.queryForm.sheet) {
|
||||
console.warn('表名不存在,无法获取列表数据');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
state.loading.list = true;
|
||||
state.error = null;
|
||||
|
||||
const result = await obtainTheList(state.queryForm);
|
||||
|
||||
if (result?.code === 200) {
|
||||
state.tableData = result.data || [];
|
||||
} else {
|
||||
state.error = `获取列表数据失败: 错误码 ${result?.code}`;
|
||||
console.error(state.error);
|
||||
}
|
||||
} catch (err) {
|
||||
state.error = `获取列表数据时发生错误: ${err.message}`;
|
||||
console.error(state.error, err);
|
||||
} finally {
|
||||
state.loading.list = false;
|
||||
}
|
||||
}
|
||||
// 上传excel
|
||||
function importExcel(options) {
|
||||
console.log(options);
|
||||
let formData = new FormData();
|
||||
formData.append('file', options.file);
|
||||
state.loading.list = true;
|
||||
importExcelFile({ workOrderType: state.work_order_type, projectId: currentProject.value?.id }, formData)
|
||||
.then((res) => {
|
||||
const { code } = res;
|
||||
if (code == 200) {
|
||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
||||
// 更新列表
|
||||
if (state.work_order_type == 3) {
|
||||
getVersionNums(false);
|
||||
} else {
|
||||
getVersionNums();
|
||||
}
|
||||
} else {
|
||||
proxy.$modal.msgError(res.msg || '导入失败');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
proxy.$modal.msgError(err.msg || '导入失败');
|
||||
})
|
||||
.finally(() => {
|
||||
state.loading.list = false;
|
||||
});
|
||||
}
|
||||
// 切换表名
|
||||
function handleChange(sheet) {
|
||||
state.queryForm.sheet = sheet;
|
||||
handleQueryList();
|
||||
}
|
||||
// 切换版本号
|
||||
function handleChangeVersion(versions) {
|
||||
state.queryForm.versions = versions;
|
||||
state.versionsData = state.options.find((e) => e.versions == versions);
|
||||
console.log('state.versionsData', state.versionsData);
|
||||
state.sheets = [];
|
||||
handleQueryList();
|
||||
}
|
||||
// 在 openTable 方法中通过索引获取对应的表格实例
|
||||
function openTable(flag, index) {
|
||||
nextTick(() => {
|
||||
// 通过索引获取当前标签页的表格实例
|
||||
const currentTable = tableRef.value[index];
|
||||
console.log(currentTable, index);
|
||||
if (currentTable) {
|
||||
handleArr(state.tableData, flag, currentTable);
|
||||
}
|
||||
});
|
||||
}
|
||||
function handleArr(arr, flag, table) {
|
||||
arr.forEach((i) => {
|
||||
table.toggleRowExpansion(i, flag);
|
||||
if (i.children) {
|
||||
handleArr(i.children, flag, table);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 审批
|
||||
function clickApprovalSheet(row) {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/billofQuantities/indexEdit`,
|
||||
query: {
|
||||
id: state.queryForm.versions,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
}
|
||||
// 审核流程
|
||||
function lookApprovalFlow(row) {
|
||||
proxy.$router.push({
|
||||
path: `/approval/billofQuantities/indexEdit`,
|
||||
query: {
|
||||
id: state.queryForm.versions,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.billof-quantities {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
357
src/views/design/billofQuantities/indexEdit.vue
Normal file
357
src/views/design/billofQuantities/indexEdit.vue
Normal file
@ -0,0 +1,357 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.versions"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">物资设备清单</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="版本号" prop="formNo">
|
||||
<el-input disabled v-model="form.versions" placeholder="请输入文件名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
<el-table :data="tableData" style="width: 100%; margin-bottom: 20px; height: calc(100vh - 305px)" row-key="id" border>
|
||||
<el-table-column prop="num" label="编号" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="specification" label="规格" />
|
||||
<el-table-column prop="unit" label="单位" />
|
||||
<el-table-column prop="quantity" label="数量" />
|
||||
<el-table-column prop="remark" label="备注" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
import { detailsMaterialAndEquipmentApproval } from '@/api/design/billofQuantities/index';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_equipmentList',
|
||||
label: '工程量清单审核'
|
||||
}
|
||||
];
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined,
|
||||
originalName: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
tableData: [],
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules, tableData } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await detailsMaterialAndEquipmentApproval(routeParams.value.id);
|
||||
console.log('res.data', res.data);
|
||||
|
||||
Object.assign(form.value, res.data);
|
||||
console.log('form', form.value);
|
||||
|
||||
tableData.value = res.data.auditData;
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.versions;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.versions);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
console.log('routeParams.value', routeParams.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
163
src/views/design/condition/comm/filePage.vue
Normal file
163
src/views/design/condition/comm/filePage.vue
Normal file
@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<div class="box_btn">
|
||||
<file-upload :limit="1" :uploadUrl="uploadUrl" :params="uploadParams" :on-upload-success="uploadFile" :fileType="[]">
|
||||
<el-button type="primary" style="float: left">
|
||||
<el-icon size="small"><Upload /></el-icon>上传文件
|
||||
</el-button>
|
||||
</file-upload>
|
||||
</div>
|
||||
</el-col>
|
||||
<right-toolbar @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table :data="FileList" style="width: 100%" height="64vh">
|
||||
<el-table-column type="index" align="center" label="序号" width="180" />
|
||||
<el-table-column prop="fileName" align="center" label="文件名称" />
|
||||
<el-table-column label="流程状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Download" @click="onExport(scope.row.fileUrl)">下载</el-button>
|
||||
<el-button type="success" link icon="edit" v-show="scope.row.status == 'draft'" @click="onUpdate(scope.row)">审核</el-button>
|
||||
<el-button link type="warning" v-show="scope.row.status != 'draft'" icon="View" @click="onView(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="getList" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="DataCollectionForm" lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { collectFileList } from '@/api/design/condition';
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const uploadUrl = computed(() => {
|
||||
return `/design/collectFile/upload`;
|
||||
});
|
||||
// 父组件传递的参数接受
|
||||
const props = defineProps({
|
||||
catalogueId: {
|
||||
type: Number
|
||||
}
|
||||
});
|
||||
|
||||
const uploadParams = ref({
|
||||
catalogueId: '',
|
||||
projectId: currentProject.value?.id
|
||||
});
|
||||
const total = ref(0);
|
||||
const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
formNo: undefined,
|
||||
projectName: undefined,
|
||||
submitUnit: undefined,
|
||||
specialty: undefined,
|
||||
submitDate: undefined,
|
||||
volumeName: undefined,
|
||||
volumeNo: undefined,
|
||||
changeReason: undefined,
|
||||
status: undefined,
|
||||
params: {},
|
||||
catalogueId: undefined
|
||||
}
|
||||
});
|
||||
const { queryParams } = toRefs(data);
|
||||
const FileList = ref([]);
|
||||
// 查询收资清单目录列表
|
||||
const getList = async () => {
|
||||
let res = await collectFileList(queryParams.value);
|
||||
if (res.code == 200) {
|
||||
FileList.value = res.rows;
|
||||
total.value = res.total;
|
||||
}
|
||||
};
|
||||
// 上传文件
|
||||
const uploadFile = (files) => {
|
||||
proxy.$modal.success('上传成功');
|
||||
console.log(files);
|
||||
getList();
|
||||
};
|
||||
const onUpdate = (row) => {
|
||||
// 审核
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/condition/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
const onView = (row) => {
|
||||
// 查看流程
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/condition/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
const onExport = (fileUrl) => {
|
||||
if (!fileUrl) {
|
||||
proxy.$modal.error('文件地址不存在,无法下载');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 创建一个隐藏的a标签
|
||||
const link = document.createElement('a');
|
||||
// 设置下载地址
|
||||
link.href = fileUrl;
|
||||
// 从URL中提取文件名作为下载文件名
|
||||
const fileName = fileUrl.split('/').pop();
|
||||
link.download = fileName || 'download file';
|
||||
// 触发点击事件
|
||||
link.click();
|
||||
// 下载后移除a标签
|
||||
document.body.removeChild(link);
|
||||
// 显示下载成功提示
|
||||
proxy.$modal.success('文件开始下载');
|
||||
} catch (error) {
|
||||
// proxy.$modal.error('下载失败,请稍后重试');
|
||||
}
|
||||
};
|
||||
// 页面挂载时初始化数据
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
const getInfo = (id) => {
|
||||
queryParams.value.catalogueId = id;
|
||||
uploadParams.value.catalogueId = id;
|
||||
getList();
|
||||
};
|
||||
defineExpose({
|
||||
getInfo
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.condition {
|
||||
.el-tabs__header {
|
||||
height: 84vh !important;
|
||||
}
|
||||
}
|
||||
</style>
|
156
src/views/design/condition/index.vue
Normal file
156
src/views/design/condition/index.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div class="p-6 bg-gray-50 condition">
|
||||
<div class="file-category">
|
||||
<span style="color: #757575; display: inline-block; margin-bottom: 15px">文件分类</span>
|
||||
<!-- 优化了图标与文字的对齐和间距 -->
|
||||
<div v-for="(item, i) of FolderList" :key="i" :class="{ active: currentActive === i }" @click="handleClick(item, i)" class="category-item">
|
||||
<el-icon :size="20" class="folder-icon">
|
||||
<Folder />
|
||||
</el-icon>
|
||||
<span class="folder-name">
|
||||
{{ item.catalogueName }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxs">
|
||||
<filePage :catalogueId="catalogueId" ref="filePageRef"></filePage>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="DataCollectionForm" lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { collectCatalogueList } from '@/api/design/condition';
|
||||
import filePage from './comm/filePage.vue';
|
||||
const filePageRef = ref<typeof filePage | null>(null);
|
||||
const activeName = ref('');
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const FolderList = ref([]);
|
||||
const catalogueId = ref(0);
|
||||
// 查询收资清单目录列表
|
||||
const getList = async () => {
|
||||
let res = await collectCatalogueList({ projectId: currentProject.value?.id });
|
||||
if (res.code == 200) {
|
||||
FolderList.value = res.rows;
|
||||
catalogueId.value = res.rows[0].id; //默认第一个
|
||||
nextTick(() => {
|
||||
filePageRef.value?.getInfo(catalogueId.value); //重新加载当前页
|
||||
});
|
||||
}
|
||||
};
|
||||
// 当前激活项的索引
|
||||
const currentActive = ref(0);
|
||||
|
||||
// 点击事件处理函数
|
||||
const handleClick = (item, index) => {
|
||||
currentActive.value = index;
|
||||
catalogueId.value = item.id;
|
||||
nextTick(() => {
|
||||
filePageRef.value?.getInfo(item.id); //重新加载当前页
|
||||
});
|
||||
};
|
||||
// 页面挂载时初始化数据
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.condition {
|
||||
display: flex;
|
||||
.el-tabs__header {
|
||||
height: 90vh !important;
|
||||
}
|
||||
.file-category {
|
||||
width: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* 移除固定宽度,让容器根据内容自适应 */
|
||||
background-color: #ffffff;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
/* 限制最大宽度,防止内容过长 */
|
||||
/* max-width: 200px; */
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.file-category > div {
|
||||
cursor: pointer;
|
||||
padding: 8px 12px;
|
||||
margin-bottom: 4px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
/* 文本不换行,确保宽度由内容决定 */
|
||||
white-space: nowrap;
|
||||
transition: all 0.2s ease;
|
||||
> span {
|
||||
margin-left: 6px;
|
||||
/* color: #676767;
|
||||
font-size: 18px; */
|
||||
}
|
||||
}
|
||||
|
||||
.file-category {
|
||||
width: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #ffffff;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
margin-right: 10px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
// 分类项样式优化
|
||||
.category-item {
|
||||
cursor: pointer;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 4px;
|
||||
border-radius: 6px;
|
||||
display: inline-flex;
|
||||
align-items: center; /* 垂直居中对齐 */
|
||||
white-space: nowrap;
|
||||
transition: all 0.25s ease;
|
||||
font-size: 14px;
|
||||
color: #334155;
|
||||
line-height: 1; /* 确保行高一致 */
|
||||
|
||||
&:hover {
|
||||
background-color: #f1f5f9;
|
||||
transform: translateX(2px);
|
||||
}
|
||||
}
|
||||
|
||||
// 图标样式
|
||||
.folder-icon {
|
||||
color: #94a3b8;
|
||||
transition: color 0.25s ease;
|
||||
}
|
||||
|
||||
// 文件夹名称样式
|
||||
.folder-name {
|
||||
margin-left: 8px; /* 增加图标与文字间距 */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(100% - 30px); /* 限制最大宽度,防止溢出 */
|
||||
}
|
||||
|
||||
// 活跃状态样式
|
||||
.category-item.active {
|
||||
background-color: #eff6ff;
|
||||
color: #2563eb;
|
||||
font-weight: 500;
|
||||
|
||||
.folder-icon {
|
||||
color: #2563eb;
|
||||
}
|
||||
}
|
||||
.boxs {
|
||||
width: calc(100% - 220px);
|
||||
}
|
||||
}
|
||||
</style>
|
353
src/views/design/condition/indexEdit.vue
Normal file
353
src/views/design/condition/indexEdit.vue
Normal file
@ -0,0 +1,353 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">设计输入条件</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="文件名称" prop="formNo">
|
||||
<el-input disabled v-model="form.fileName" placeholder="请输入文件名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="文件" prop="formNo">
|
||||
<div style="display: flex">
|
||||
<span style="color: rgb(50, 142, 248)" @click="onOpen">点击打开</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
import { getKnowledgeDocument } from '@/api/design/technicalStandard';
|
||||
import { getCollectFile } from '@/api/design/condition';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_collectFile',
|
||||
label: '设计输入文件'
|
||||
}
|
||||
];
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined,
|
||||
originalName: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
rules: {}
|
||||
});
|
||||
const onOpen = () => {
|
||||
window.open(form.value.fileUrl, '_blank');
|
||||
};
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getCollectFile(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
console.log(routeParams.value.type);
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
285
src/views/design/designChange/index.vue
Normal file
285
src/views/design/designChange/index.vue
Normal file
@ -0,0 +1,285 @@
|
||||
<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" label-width="110px">
|
||||
<el-form-item label="申请单编号" prop="formNo">
|
||||
<el-input v-model="queryParams.formNo" placeholder="请输入申请单编号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="工程名称" prop="projectName">
|
||||
<el-input v-model="queryParams.projectName" placeholder="请输入工程名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="卷册号" prop="volumeNo">
|
||||
<el-input v-model="queryParams.volumeNo" placeholder="请输入卷册号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:designChange:list']">搜索</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">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="ChatRound" @click="handleAdd" v-hasPermi="['design:designChange:add']">下发变更通知</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="designChangeList">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="申请单编号" align="center" prop="formNo" width="150" />
|
||||
<el-table-column label="工程名称" align="center" prop="projectName" width="150" />
|
||||
<el-table-column label="提出单位" align="center" prop="submitUnit" width="150" />
|
||||
<el-table-column label="专业" align="center" prop="specialtyName" width="120" />
|
||||
<el-table-column label="提出日期" align="center" prop="submitDate" width="150">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.submitDate, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卷册号" align="center" prop="volumeNo" width="150" />
|
||||
<el-table-column label="流程状态" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag v-if="scope.row.fileId != null" :options="wf_business_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更文件" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.ossVoList && scope.row.ossVoList.length > 0"
|
||||
icon="View"
|
||||
@click="handleDesignView(scope.row)"
|
||||
>查看文件</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更原因" align="center" prop="changeReason" width="150">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="design_change_reason_type" :value="scope.row.changeReason ? scope.row.changeReason.split(',') : []" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更内容" align="center" prop="changeContent" width="150" />
|
||||
<el-table-column label="备注" align="center" prop="remark" width="150" />
|
||||
<el-table-column label="操作" fixed="right" width="300">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="Upload"
|
||||
@click="handleAddChange(scope.row)"
|
||||
v-if="scope.row.status == 'draft' || scope.row.status == 'back'"
|
||||
>上传</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
link
|
||||
icon="View"
|
||||
v-if="scope.row.status != 'draft'"
|
||||
v-hasPermi="['design:designChange:query']"
|
||||
@click="handleViewInfo(scope.row)"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button type="success" link icon="View" v-hasPermi="['design:designChange:query']" @click="handleViewDetail(scope.row)"
|
||||
>通知单</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
link
|
||||
icon="View"
|
||||
v-hasPermi="['design:designChange:query']"
|
||||
v-if="scope.row.status == 'back' || scope.row.status == 'termination'"
|
||||
@click="handleViewHistory(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="getList" />
|
||||
</el-card>
|
||||
<wordDetial ref="wordDetialRef"></wordDetial>
|
||||
<el-dialog draggable title="文件列表" v-model="viewVisible" width="500px">
|
||||
<el-table v-if="fileList.length > 0" :data="fileList" style="width: 100%" border>
|
||||
<el-table-column prop="fileName" label="文件名称" align="center">
|
||||
<template #default="scope">
|
||||
<el-link
|
||||
:key="scope.row.fileId"
|
||||
:href="scope.row.fileUrl"
|
||||
target="_blank"
|
||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||
:underline="false"
|
||||
>
|
||||
{{ scope.row.originalName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="170" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="success" link icon="View" @click="handleDownload(scope.row)"> 查看 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-else class="empty-list text-center">暂无文件</div>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button type="primary" @click="viewVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog title="单据" v-model="viewDetailVisible" width="800px">
|
||||
<histroy ref="histroyRef"></histroy>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="DesignChange" lang="ts">
|
||||
import { listDesignChange, delDesignChange } from '@/api/design/designChange';
|
||||
import { DesignChangeVO } from '@/api/design/designChange/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import wordDetial from '@/components/wordDetial/index';
|
||||
import histroy from '../volumeCatalog/comm/histroy.vue';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const designChangeList = ref<DesignChangeVO[]>([]);
|
||||
const wordDetialRef = ref<InstanceType<typeof wordDetial>>();
|
||||
const histroyRef = ref<InstanceType<typeof histroy>>();
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const uploadUrl = computed(() => {
|
||||
return `/design/collectFile/upload`;
|
||||
});
|
||||
const viewVisible = ref(false);
|
||||
const fileList = ref([]);
|
||||
const ossid = ref(null);
|
||||
const viewDetailVisible = ref(false);
|
||||
const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
formNo: undefined,
|
||||
projectName: undefined,
|
||||
submitUnit: undefined,
|
||||
specialty: undefined,
|
||||
submitDate: undefined,
|
||||
volumeName: undefined,
|
||||
volumeNo: undefined,
|
||||
changeReason: undefined,
|
||||
status: undefined,
|
||||
params: {}
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
/** 查询设计变更管理列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listDesignChange(queryParams.value);
|
||||
designChangeList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
/** 下发通知 */
|
||||
const handleAdd = () => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/designChange/indexEdit`,
|
||||
query: {
|
||||
type: 'add'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 查看详情 */
|
||||
const handleViewDetail = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/designChange/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
// 上传变更图纸
|
||||
const handleAddChange = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/drawing/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'add'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 查看流程操作 */
|
||||
const handleViewInfo = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/drawing/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 删除按钮操作 */
|
||||
const handleDesignView = async (row?: DesignChangeVO) => {
|
||||
fileList.value = row.ossVoList;
|
||||
viewVisible.value = true;
|
||||
};
|
||||
const handleViewHistory = async (row) => {
|
||||
// 查看历史流程记录
|
||||
viewDetailVisible.value = true;
|
||||
nextTick(() => {
|
||||
histroyRef.value?.getList(row.id);
|
||||
});
|
||||
};
|
||||
// 预览
|
||||
const onOpen = (path: string) => {
|
||||
window.open(path, '_blank');
|
||||
};
|
||||
const handleDownload = (row: any) => {
|
||||
window.open(row.url, '_blank');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
437
src/views/design/designChange/indexEdit.vue
Normal file
437
src/views/design/designChange/indexEdit.vue
Normal file
@ -0,0 +1,437 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50 designChangeForm">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 表单区域 -->
|
||||
<div v-if="routeParams.type == 'view'" style="width: 100%; text-align: right; margin-bottom: 10px">
|
||||
<el-button @click="goBack" size="large" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>返回</el-button
|
||||
>
|
||||
</div>
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">下发变更通知信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请单编号" prop="formNo">
|
||||
<el-input v-model="form.formNo" placeholder="请输入申请单编号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工程名称" prop="projectName">
|
||||
<el-input v-model="form.projectName" placeholder="请输入工程名称" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原卷册号" prop="volumeNo">
|
||||
<el-select
|
||||
id="projectSelect"
|
||||
v-model="form.volumeNo"
|
||||
placeholder="请选择原卷册号"
|
||||
clearable
|
||||
filterable
|
||||
@change="handleSelect"
|
||||
style="width: 150px; margin-right: 20px"
|
||||
>
|
||||
<el-option
|
||||
v-for="project in volumeCatalogList"
|
||||
:key="project.volumeNumber"
|
||||
:label="project.volumeNumber"
|
||||
:value="project.volumeNumber"
|
||||
/>
|
||||
</el-select> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="提出单位" prop="submitUnit">
|
||||
<el-input v-model="form.submitUnit" placeholder="请输入提出单位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业" prop="specialtyName">
|
||||
<el-input disabled v-model="form.specialtyName" placeholder="请输入专业" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="提出日期" prop="submitDate">
|
||||
<el-date-picker clearable v-model="form.submitDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择提出日期">
|
||||
</el-date-picker> </el-form-item
|
||||
></el-col>
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="卷册名称" prop="volumeName"> <el-input v-model="form.volumeName" placeholder="请输入卷册名称" /> </el-form-item
|
||||
></el-col> -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="子项名称" prop="subName">
|
||||
<el-input disabled v-model="form.extendDetail.subName" placeholder="请输入子项名称" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="原设计处置" prop="designDisposal">
|
||||
<el-radio-group v-model="form.extendDetail.designDisposal">
|
||||
<el-radio value="1" size="large">原图作废</el-radio>
|
||||
<el-radio value="2" size="large">原图保留,部分修改</el-radio>
|
||||
<el-radio value="3" size="large">原图保留,补充设计</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="24" v-if="form.extendDetail.designDisposal == 2 && form.volumeNo">
|
||||
<el-form-item label="选择保留文件" prop="designPhase">
|
||||
<el-select
|
||||
id="projectSelect"
|
||||
v-model="form.saveFile"
|
||||
placeholder="请选择保留文件"
|
||||
multiple
|
||||
style="width: 150px; margin-right: 20px"
|
||||
>
|
||||
<el-option v-for="project in fileVoList" :key="project.id" :label="project.fileName" :value="project.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计阶段" prop="designPhase">
|
||||
<el-input v-model="form.extendDetail.designPhase" placeholder="请输入设计阶段" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="变更类别" prop="changeCategory">
|
||||
<el-radio-group v-model="form.extendDetail.changeCategory">
|
||||
<el-radio value="1" size="large">重大设计变更</el-radio>
|
||||
<el-radio value="2" size="large">一般设计变更</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="实施程序" prop="ImpProcedure">
|
||||
<el-radio-group v-model="form.extendDetail.ImpProcedure">
|
||||
<el-radio value="1" size="large">建设单位重新申报初步设计审批</el-radio>
|
||||
<el-radio value="2" size="large">建设单位送原施工图审查机构审查、建设主管部分备案后交付实施</el-radio>
|
||||
<el-radio value="3" size="large">建设单位确认后交付实施</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="更改相关专业" prop="involvingProfessions">
|
||||
<el-input v-model="form.extendDetail.involvingProfessions" placeholder="请输入更改相关专业" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="附图" prop="attachmentPic"> <image-upload v-model="form.attachmentPic" :fileSize="100" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="变更原因" prop="changeReason">
|
||||
<el-checkbox-group v-model="form.changeReason">
|
||||
<el-checkbox v-for="dict in design_change_reason_type" :key="dict.value" :value="dict.value">
|
||||
{{ dict.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item></el-col
|
||||
>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="变更内容" prop="changeContent">
|
||||
<el-input v-model="form.changeContent" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="费用" prop="costEstimation">
|
||||
<el-input v-model="form.costEstimation" type="number" placeholder="请输入费用" /> </el-form-item
|
||||
></el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="变更费用估算表" label-width="110px" prop="costEstimationFile">
|
||||
<file-upload v-model="form.costEstimationFile" :fileSize="100" /> </el-form-item
|
||||
></el-col>
|
||||
<!-- <el-col :span="24">
|
||||
<el-form-item label="变更文件" prop="fileId"> <file-upload v-model="form.fileId" :fileSize="100" /> </el-form-item
|
||||
></el-col> -->
|
||||
<el-col :span="24"
|
||||
><el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> </el-form-item
|
||||
></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="flex justify-center gap-4 mt-8">
|
||||
<el-button
|
||||
v-if="routeParams.type != 'view'"
|
||||
@click="goBack"
|
||||
size="large"
|
||||
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>返回</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
v-if="routeParams.type != 'view'"
|
||||
@click="submitForm"
|
||||
class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { addDesignChange, getDesignChange } from '@/api/design/designChange';
|
||||
import { listVolumeCatalog } from '@/api/design/volumeCatalog';
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const volumeCatalogList = ref([]);
|
||||
let volumeMap = new Map();
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const fileVoList = ref([]);
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
formNo: undefined,
|
||||
projectName: undefined,
|
||||
submitUnit: undefined,
|
||||
specialty: undefined,
|
||||
specialtyName: undefined,
|
||||
submitDate: undefined,
|
||||
volumeName: undefined,
|
||||
volumeNo: undefined,
|
||||
attachmentPic: undefined,
|
||||
changeReason: [],
|
||||
changeContent: undefined,
|
||||
costEstimation: undefined,
|
||||
costEstimationFile: undefined,
|
||||
fileId: undefined,
|
||||
status: undefined,
|
||||
remark: undefined,
|
||||
saveFile: undefined,
|
||||
extendDetail: {
|
||||
changeCategory: undefined,
|
||||
ImpProcedure: undefined,
|
||||
involvingProfessions: undefined,
|
||||
subName: undefined,
|
||||
designDisposal: undefined,
|
||||
designPhase: undefined
|
||||
}
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
fileName: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
fileStatus: undefined,
|
||||
originalName: undefined,
|
||||
newest: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
// 卷册号
|
||||
volumeNo: [{ required: true, message: '请请选择卷册号', trigger: 'change' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
//返回
|
||||
const goBack = () => {
|
||||
proxy.$tab.closePage(route);
|
||||
router.go(-1);
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
var changeReason = '';
|
||||
if (form.value.changeReason && form.value.changeReason.length > 0) {
|
||||
changeReason = form.value.changeReason.join(',');
|
||||
}
|
||||
var saveFile = '';
|
||||
if (form.value.saveFile && form.value.saveFile.length > 0) {
|
||||
saveFile = form.value.saveFile.join(',');
|
||||
}
|
||||
leaveFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
var res;
|
||||
res = await addDesignChange({ ...form.value, changeReason, saveFile }).finally(() => (buttonLoading.value = false));
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('通知成功');
|
||||
goBack();
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 查询卷册目录列表 */
|
||||
const getList = async () => {
|
||||
const res = await listVolumeCatalog({ projectId: currentProject.value?.id, auditStatus: 'finish' });
|
||||
volumeCatalogList.value = res.rows;
|
||||
volumeCatalogList.value.forEach((e) => {
|
||||
volumeMap.set(e.volumeNumber, e);
|
||||
});
|
||||
};
|
||||
const handleSelect = (val) => {
|
||||
let obj = volumeMap.get(val);
|
||||
console.log(obj);
|
||||
fileVoList.value = obj.fileVoList;
|
||||
form.value.volumeName = obj.volumeName;
|
||||
form.value.specialty = obj.specialty;
|
||||
form.value.specialtyName = obj.specialtyName;
|
||||
form.value.extendDetail.subName = obj.designSubitem;
|
||||
};
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getDesignChange(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
if (form.value.changeReason.length > 0) {
|
||||
form.value.changeReason = form.value.changeReason.split(',');
|
||||
}
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
getList();
|
||||
if (routeParams.value.type != 'add') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.designChangeForm {
|
||||
.el-select {
|
||||
width: 300px !important;
|
||||
}
|
||||
}
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
107
src/views/design/drawing/DrawingTable.vue
Normal file
107
src/views/design/drawing/DrawingTable.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<el-table v-loading="loading" :data="drawingList" height="74vh">
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column label="子项名称" align="center" prop="designSubitem" />
|
||||
<el-table-column label="专业" align="center" prop="specialty">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="des_user_major" :value="scope.row.specialty" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="负责人" align="center" prop="principal" />
|
||||
<el-table-column label="卷册号" align="center" prop="volumeNumber" />
|
||||
<el-table-column label="资料名称" align="center" prop="fileName">
|
||||
<template #default="scope">
|
||||
<el-link type="primary" :underline="false" :href="scope.row.url" target="_blank">{{ scope.row.fileName }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding " width="240">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="primary" icon="Download" @click="handleDownload(scope.row)">下载</el-button>
|
||||
<el-button size="small" type="primary" icon="view" @click="handleViewHis(scope.row)">查阅记录</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-dialog draggable title="文件列表" v-model="viewVisible" width="500px">
|
||||
<el-table :data="histroyList" style="width: 100%" border>
|
||||
<el-table-column type="index" label="序号" align="center" width="80"> </el-table-column>
|
||||
<el-table-column prop="userName" label="用户名称" align="center"> </el-table-column>
|
||||
<el-table-column prop="createTime" label="查阅时间" align="center"> </el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button type="primary" @click="viewVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps, defineEmits } from 'vue';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { volumeFileViewer, volumeFileViewerList } from '@/api/design/drawing';
|
||||
|
||||
const { des_user_major } = toRefs(proxy?.useDict('des_user_major'));
|
||||
|
||||
const props = defineProps({
|
||||
drawingList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
drawing_file_type: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
wf_business_status: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
const viewVisible = ref(false);
|
||||
const histroyList = ref([]);
|
||||
|
||||
const emits = defineEmits(['selection-change', 'view', 'update', 'delete', 'view-info', 'cancel-process-apply']);
|
||||
|
||||
const handleSelectionChange = (selection) => {
|
||||
emits('selection-change', selection);
|
||||
};
|
||||
|
||||
const handleView = (row) => {
|
||||
emits('view', row);
|
||||
};
|
||||
|
||||
const handleUpdate = (row) => {
|
||||
emits('update', row);
|
||||
};
|
||||
|
||||
const handleDelete = (row) => {
|
||||
emits('delete', row);
|
||||
};
|
||||
|
||||
const handleViewInfo = (row) => {
|
||||
emits('view-info', row);
|
||||
};
|
||||
|
||||
const handleCancelProcessApply = (id) => {
|
||||
emits('cancel-process-apply', id);
|
||||
};
|
||||
const handleViewHis = async (row) => {
|
||||
viewVisible.value = true;
|
||||
let res = await volumeFileViewerList(row.volumeFileId);
|
||||
if (res.code == 200) {
|
||||
histroyList.value = res.rows;
|
||||
}
|
||||
};
|
||||
const handleDownload = (row) => {
|
||||
getCheck(row);
|
||||
proxy?.$download.oss(row.fileUrl);
|
||||
};
|
||||
// 调用查阅接口
|
||||
const getCheck = async (row) => {
|
||||
volumeFileViewer({ volumeFileId: row.volumeFileId });
|
||||
};
|
||||
</script>
|
242
src/views/design/drawing/index.vue
Normal file
242
src/views/design/drawing/index.vue
Normal file
@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<div class="p-2 volumeCatalog">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="卷册号" prop="volumeNumber">
|
||||
<el-input v-model="queryParams.volumeNumber" placeholder="请输入卷册号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="资料名称" prop="documentName">
|
||||
<el-input v-model="queryParams.documentName" placeholder="请输入资料名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:volumeCatalog:query']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['design:volumeCatalog:query']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="volumeCatalogList">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="子项名称" align="center" prop="designSubitem" />
|
||||
<el-table-column label="专业" align="center" prop="specialtyName"> </el-table-column>
|
||||
<el-table-column label="设计人员" align="center" prop="principalName" />
|
||||
<el-table-column label="卷册号" align="center" prop="volumeNumber" />
|
||||
<el-table-column label="资料名称" align="center" prop="documentName" />
|
||||
<el-table-column label="图纸文件" align="center" prop="remark" width="150">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['design:volumeFile:query']">查看文件</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>
|
||||
<!-- 查看文件列表 -->
|
||||
<el-dialog draggable title="文件列表" v-model="viewVisible" width="800px">
|
||||
<el-table :data="fileList" style="width: 100%" border>
|
||||
<el-table-column prop="fileName" label="文件" align="center">
|
||||
<template #default="scope">
|
||||
<el-link
|
||||
:key="scope.row.fileId"
|
||||
:href="scope.row.fileUrl"
|
||||
target="_blank"
|
||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||
:underline="false"
|
||||
@click="handleBookFile(scope.row)"
|
||||
>
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="size" label="状态" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">{{ scope.row.status == 1 ? '使用中' : '已作废' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="240" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="view" @click="handleViewHis(scope.row)">查阅记录</el-button>
|
||||
<el-button type="danger" link icon="Download" @click="handleDownload(scope.row)"> 下载 </el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button type="primary" @click="viewVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog draggable title="文件列表" v-model="viewVisible1" width="500px">
|
||||
<el-table :data="histroyList" style="width: 100%" border>
|
||||
<el-table-column type="index" label="序号" align="center" width="80"> </el-table-column>
|
||||
<el-table-column prop="userName" label="用户名称" align="center"> </el-table-column>
|
||||
<el-table-column prop="createTime" label="查阅时间" align="center"> </el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button type="primary" @click="viewVisible1 = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="VolumeCatalog" lang="ts">
|
||||
import { listVolumeCatalog, addVolumeCatalog, updateVolumeCatalog } from '@/api/design/volumeCatalog';
|
||||
import { VolumeCatalogVO } from '@/api/design/volumeCatalog/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { volumeFileViewer, volumeFileViewerList } from '@/api/design/drawing';
|
||||
const fileList = ref([]);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const volumeCatalogList = ref<VolumeCatalogVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const volumeCatalogFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const uploadForm = reactive({
|
||||
userIds: [],
|
||||
volumeCatalogId: undefined,
|
||||
fileId: undefined,
|
||||
explainText: '',
|
||||
fileList: [],
|
||||
cancellationIds: [] // 用于存储已作废的文件ID
|
||||
});
|
||||
const initFormData: any = {
|
||||
design: undefined,
|
||||
projectId: currentProject.value?.id || '',
|
||||
designSubitemId: undefined,
|
||||
volumeNumber: undefined,
|
||||
documentName: undefined,
|
||||
designState: '2',
|
||||
|
||||
remark: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
designSubitemId: undefined,
|
||||
volumeNumber: undefined,
|
||||
documentName: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
design: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
volumeNumber: [{ required: true, message: '卷册号不能为空', trigger: 'blur' }],
|
||||
documentName: [{ required: true, message: '资料名称不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
const histroyList = ref([]);
|
||||
/** 查询卷册目录列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listVolumeCatalog(queryParams.value);
|
||||
volumeCatalogList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
const handleView = (row?: any) => {
|
||||
fileList.value = row.fileVoList;
|
||||
|
||||
viewVisible.value = true;
|
||||
};
|
||||
|
||||
const viewVisible = ref(false);
|
||||
const viewVisible1 = ref(false);
|
||||
/** 重置上传表单 */
|
||||
const resetUploadForm = () => {
|
||||
uploadForm.userIds = [];
|
||||
uploadForm.volumeCatalogId = undefined;
|
||||
uploadForm.fileId = undefined;
|
||||
uploadForm.explainText = '';
|
||||
uploadForm.fileList = [];
|
||||
uploadForm.cancellationIds = []; // 重置作废文件ID列表
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
volumeCatalogFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.design) {
|
||||
await updateVolumeCatalog(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addVolumeCatalog(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleDownload = (row: any) => {
|
||||
getCheck(row);
|
||||
proxy?.$download.oss(row.fileId);
|
||||
};
|
||||
const handleBookFile = (row: any) => {
|
||||
getCheck(row);
|
||||
};
|
||||
// 调用查阅接口
|
||||
const getCheck = async (row) => {
|
||||
volumeFileViewer({ volumeFileId: row.fileId });
|
||||
};
|
||||
const handleViewHis = async (row) => {
|
||||
viewVisible1.value = true;
|
||||
let res = await volumeFileViewerList(row.fileId);
|
||||
if (res.code == 200) {
|
||||
histroyList.value = res.rows;
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
form.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
385
src/views/design/drawing/indexEdit.vue
Normal file
385
src/views/design/drawing/indexEdit.vue
Normal file
@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">变更图纸信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="图纸文件" prop="fileId" class="mb-2 md:col-span-2">
|
||||
<file-upload :fileType="['pdf']" v-model="form.fileId" class="w-full"></file-upload>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getDrawing } from '@/api/design/drawing';
|
||||
import { updateDesignChange, getDesignChange } from '@/api/design/designChange';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_designchanged',
|
||||
label: '变更图纸审批'
|
||||
}
|
||||
];
|
||||
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
versionNumber: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
originalName: undefined,
|
||||
remark: undefined,
|
||||
fileId: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
fileName: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
fileStatus: undefined,
|
||||
originalName: undefined,
|
||||
newest: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
fileId: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 新增时必须上传文件
|
||||
if (!form.value.fileId) {
|
||||
callback(new Error('请上传变更图纸文件'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getDesignChange(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
leaveFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
var res;
|
||||
// if (form.value.id) {
|
||||
res = await updateDesignChange({ ...form.value, id: routeParams.value.id }).finally(() => (buttonLoading.value = false));
|
||||
// }
|
||||
if (res.code == 200) {
|
||||
dialog.visible = false;
|
||||
submit(status.value, res.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
||||
// submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
console.log(data);
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
369
src/views/design/drawingreview/detailForm.vue
Normal file
369
src/views/design/drawingreview/detailForm.vue
Normal file
@ -0,0 +1,369 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" class="info-form">
|
||||
<!-- 基本信息区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<el-divider content-position="left">
|
||||
<span class="title-text">基本信息</span>
|
||||
</el-divider>
|
||||
</div>
|
||||
<el-row :gutter="20" class="section-content">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="编号" prop="num">
|
||||
<el-input v-model="formData.num" placeholder="请输入编号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业" prop="professional">
|
||||
<el-input v-model="formData.professional" placeholder="请输入专业" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计阶段" prop="stage">
|
||||
<el-input v-model="formData.stage" placeholder="请输入设计阶段" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="卷册" prop="volume">
|
||||
<el-input v-model="formData.volume" placeholder="请输入卷册" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 项目信息区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<el-divider content-position="left">
|
||||
<span class="title-text">项目信息</span>
|
||||
</el-divider>
|
||||
</div>
|
||||
<el-row :gutter="20" class="section-content">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目" prop="projectName">
|
||||
<el-input disabled v-model="formData.projectName" placeholder="请输入项目ID" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="子项目" prop="subprojectId">
|
||||
<el-select v-model="formData.subprojectId" clearable placeholder="请选择子项目" style="width: 300px">
|
||||
<el-option v-for="item in subProjectList" :key="item.id" :label="item.projectName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 人员信息区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<el-divider content-position="left">
|
||||
<span class="title-text">人员信息</span>
|
||||
</el-divider>
|
||||
</div>
|
||||
<el-row :gutter="20" class="section-content">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计人" prop="designer">
|
||||
<el-input v-model="formData.designer" placeholder="请输入设计人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="校审人员" prop="proofreading">
|
||||
<el-input v-model="formData.proofreading" placeholder="请输入校审人员" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="校审人员ID" prop="proofreadingId">
|
||||
<el-input v-model="formData.proofreadingId" placeholder="请输入校审人员ID" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="校审时间" prop="proofreadingDate">
|
||||
<el-date-picker
|
||||
v-model="formData.proofreadingDate"
|
||||
type="date"
|
||||
placeholder="选择校审时间"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="审核人员" prop="audit">
|
||||
<el-input v-model="formData.audit" placeholder="请输入审核人员" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="审核人员ID" prop="auditId">
|
||||
<el-input v-model="formData.auditId" placeholder="请输入审核人员ID" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="审核时间" prop="auditDate">
|
||||
<el-date-picker v-model="formData.auditDate" type="date" placeholder="选择审核时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="执行人员" prop="executor">
|
||||
<el-input v-model="formData.executor" placeholder="请输入执行人员" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="执行人员ID" prop="executorId">
|
||||
<el-input v-model="formData.executorId" placeholder="请输入执行人员ID" />
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="执行时间" prop="executorDate">
|
||||
<el-date-picker v-model="formData.executorDate" type="date" placeholder="选择执行时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 意见和内容区域 -->
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<el-divider content-position="left">
|
||||
<span class="title-text">意见和内容</span>
|
||||
</el-divider>
|
||||
</div>
|
||||
<el-row :gutter="20" class="section-content">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="验证内容" prop="verificationContent">
|
||||
<el-input v-model="formData.verificationContent" type="textarea" placeholder="请输入验证内容" :rows="4" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="验证意见" prop="verificationOpinion">
|
||||
<el-input v-model="formData.verificationOpinion" type="textarea" placeholder="请输入验证意见" :rows="4" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="执行意见" prop="executionOpinion">
|
||||
<el-input v-model="formData.executionOpinion" type="textarea" placeholder="请输入执行意见" :rows="4" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup name="ExamineForm" lang="ts">
|
||||
import { ref, watch, reactive } from 'vue';
|
||||
import { fillOutTheDesignVerificationForm, drawingreviewReceipts } from '@/api/design/drawingreview';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { computed } from 'vue';
|
||||
import { subProjectListAll } from '@/api/design/drawingreview';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
console.log(currentProject.value);
|
||||
const subProjectList = ref([]);
|
||||
let subProjectMap = new Map();
|
||||
// 定义表单数据类型
|
||||
interface FormData {
|
||||
num: string;
|
||||
professional: string;
|
||||
stage: string;
|
||||
volume: string;
|
||||
projectId: string;
|
||||
projectName: string;
|
||||
subprojectId: string;
|
||||
subprojectName: string;
|
||||
designer: string;
|
||||
proofreading: string;
|
||||
proofreadingId: string;
|
||||
proofreadingDate: string;
|
||||
audit: string;
|
||||
auditId: string;
|
||||
auditDate: string;
|
||||
executor: string;
|
||||
executorId: string;
|
||||
executorDate: string;
|
||||
verificationContent: string;
|
||||
verificationOpinion: string;
|
||||
executionOpinion: string;
|
||||
}
|
||||
|
||||
// 定义表单验证规则
|
||||
const rules: FormRules = {
|
||||
num: [{ required: true, message: '请输入编号', trigger: 'blur' }],
|
||||
professional: [{ required: true, message: '请输入专业', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
// 表单数据 - 直接在组件内定义,不再通过Props接收
|
||||
const formData = reactive<FormData>({
|
||||
num: '',
|
||||
professional: '',
|
||||
stage: '',
|
||||
volume: '',
|
||||
projectId: currentProject.value?.id || '',
|
||||
projectName: currentProject.value?.name || '',
|
||||
subprojectId: '',
|
||||
subprojectName: '',
|
||||
designer: '',
|
||||
proofreading: '',
|
||||
proofreadingId: '',
|
||||
proofreadingDate: '',
|
||||
audit: '',
|
||||
auditId: '',
|
||||
auditDate: '',
|
||||
executor: '',
|
||||
executorId: '',
|
||||
executorDate: '',
|
||||
verificationContent: '',
|
||||
verificationOpinion: '',
|
||||
executionOpinion: ''
|
||||
});
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
|
||||
// 监听项目变化,可自动填充表单项目信息
|
||||
watch(
|
||||
currentProject,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// 根据实际项目结构调整赋值字段
|
||||
formData.projectId = newVal.id || '';
|
||||
formData.projectName = newVal.name || '';
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
// 通过项目获取子项目 - 监听项目 id 变化,可自动获取子项目
|
||||
const getSubProject = async () => {
|
||||
let res = await subProjectListAll(currentProject.value?.id);
|
||||
subProjectList.value = res.data;
|
||||
subProjectList.value.forEach((item: any) => {
|
||||
subProjectMap.set(item.id, item.projectName);
|
||||
});
|
||||
};
|
||||
// 验证表单
|
||||
const validate = async () => {
|
||||
if (formRef.value) {
|
||||
return await formRef.value.validate();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetFields = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
};
|
||||
|
||||
// 获取表单数据
|
||||
const getFormData = (): FormData => {
|
||||
return { ...formData };
|
||||
};
|
||||
|
||||
// 设置表单数据
|
||||
const setFormData = (data: Partial<FormData>) => {
|
||||
Object.assign(formData, data);
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const submit = async (businessId) => {
|
||||
try {
|
||||
// 先验证表单
|
||||
const isValid = await validate();
|
||||
if (isValid) {
|
||||
formData.subprojectName = subProjectMap.get(formData.subprojectId);
|
||||
formData.drawingreviewId = businessId;
|
||||
const res = await drawingreviewReceipts(formData);
|
||||
if (res.code === 200) {
|
||||
// // 提交成功处理逻辑
|
||||
// console.log('提交成功');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error);
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
getSubProject();
|
||||
});
|
||||
// 暴露方法给父组件(如果需要)
|
||||
defineExpose({
|
||||
validate,
|
||||
resetFields,
|
||||
getFormData,
|
||||
setFormData,
|
||||
submit
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 表单整体样式 */
|
||||
.info-form {
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 模块容器样式 */
|
||||
.form-section {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
/* 最后一个模块去掉底部边框 */
|
||||
.form-section:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* 模块标题样式 */
|
||||
.section-title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
padding: 0 10px;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 模块内容区域 */
|
||||
.section-content {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
/* 表单项间距调整 */
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
/* 文本域样式优化 */
|
||||
::v-deep .el-textarea__inner {
|
||||
min-height: 100px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 768px) {
|
||||
.info-form {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
384
src/views/design/drawingreview/index.vue
Normal file
384
src/views/design/drawingreview/index.vue
Normal file
@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<div class="p-2 drawingreview">
|
||||
<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="['design:drawingreview:add']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="drawingreviewList">
|
||||
<el-table-column type="index" label="序号" width="100" align="center" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName" />
|
||||
<el-table-column label="流程状态" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.auditType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-row :gutter="10" class="mb8"
|
||||
><el-col :span="1.5" v-if="scope.row.auditType === 'draft' || scope.row.auditType === 'cancel' || scope.row.auditType === 'back'">
|
||||
<el-button size="small" type="primary" icon="Edit" @click="handleUpdate(scope.row)">审核</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" size="small" icon="View" v-if="scope.row.auditType != 'draft'" @click="handleViewInfo(scope.row)"
|
||||
>查看流程</el-button
|
||||
> </el-col
|
||||
><el-col :span="1.5">
|
||||
<el-button type="warning" size="small" icon="View" v-if="scope.row.auditType != 'draft'" @click="handleViewHistory(scope.row)"
|
||||
>查看历史</el-button
|
||||
>
|
||||
</el-col></el-row
|
||||
>
|
||||
</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="drawingreviewFormRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="图纸文件" prop="auditType">
|
||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="importExcel">
|
||||
<template #trigger>
|
||||
<el-button type="primary">上传excel</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" 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="dialog.visible = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog draggable title="查看历史" v-model="dialogHistory" width="800px" append-to-body>
|
||||
<div>
|
||||
<span>选择历史退回记录:</span>
|
||||
<el-select v-model="hisId" placeholder="请选择" style="width: 240px" @change="handleShowInfo">
|
||||
<el-option v-for="item in hisList" :key="item.id" :label="item.id" :value="item.id" />
|
||||
</el-select>
|
||||
<div style="margin-top: 20px">
|
||||
<span style="color: #0d9df5">查看excel文件</span>
|
||||
<div style="margin-top: 20px" class="table-content" id="table-content">
|
||||
<el-row class="mb20" style="display: flex; justify-content: center">
|
||||
<h2>设计验证表</h2>
|
||||
</el-row>
|
||||
<el-row class="mb10" style="display: flex; justify-content: space-between">
|
||||
<div class="head-text">
|
||||
<span>编号:</span>
|
||||
<span>{{ examineForm.num }}</span>
|
||||
</div>
|
||||
<div class="head-text"></div>
|
||||
</el-row>
|
||||
<table style="width: 100%" border="1" cellspacing="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">工程名称</th>
|
||||
<td class="th-bg" colspan="10">{{ examineForm.projectName }}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2">子项名称</th>
|
||||
<td class="th-bg" colspan="6">{{ examineForm.subprojectName }}</td>
|
||||
<th colspan="2">设计阶段</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.stage }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2">专业</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.professional }}</td>
|
||||
<th colspan="2">卷册</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.volume }}</td>
|
||||
<th colspan="2">设计人</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.designer }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2">验证内容</th>
|
||||
<td class="th-bg" colspan="10">{{ examineForm.verificationContent }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="6">验证意见</th>
|
||||
<th class="th-bg" colspan="6">执行意见</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div style="height: 400px">{{ examineForm.verificationOpinion }}</div>
|
||||
</td>
|
||||
<td class="th-bg" colspan="6">
|
||||
<div style="height: 400px">{{ examineForm.executionOpinion }}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<span> 校审: {{ examineForm.proofreading }} </span>
|
||||
<span> {{ dateFormat(examineForm.proofreadingDate) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td rowspan="2" colspan="6">
|
||||
<div>执行人: {{ examineForm.executor }}</div>
|
||||
<div style="display: flex; align-items: center; justify-content: flex-end">
|
||||
{{ dateFormat(examineForm.executorDate) }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="th-bg" colspan="6">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<span>审核 : {{ examineForm.audit }}</span>
|
||||
<span> {{ dateFormat(examineForm.auditDate) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Drawingreview">
|
||||
import { computed, getCurrentInstance, toRefs } from 'vue';
|
||||
import {
|
||||
listDrawingreview,
|
||||
addDrawingreview,
|
||||
updateDrawingreview,
|
||||
ObtainHistoricalDesignDrawingsForReview,
|
||||
drawingreview
|
||||
} from '@/api/design/drawingreview';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { fromFile } from 'geotiff';
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { wf_business_status } = toRefs(proxy?.useDict('wf_business_status'));
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
const loading = ref(true);
|
||||
const buttonLoading = ref(false);
|
||||
const total = ref(0);
|
||||
const drawingreviewList = ref([]);
|
||||
const hisList = ref([]);
|
||||
const hisId = ref('');
|
||||
const fromData = new FormData();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
const dialogHistory = ref(false);
|
||||
const initexamineForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
auditType: undefined,
|
||||
remark: undefined
|
||||
};
|
||||
const drawingreviewFormRef = ref();
|
||||
const data = reactive({
|
||||
form: { ...initexamineForm },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
auditType: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
const examineForm = ref({
|
||||
audit: '',
|
||||
auditDate: '',
|
||||
auditId: '',
|
||||
designer: '',
|
||||
executionOpinion: '',
|
||||
executor: '',
|
||||
executorDate: '',
|
||||
executorId: '',
|
||||
id: '1',
|
||||
num: '',
|
||||
professional: '',
|
||||
projectId: '',
|
||||
projectName: '',
|
||||
proofreading: '',
|
||||
proofreadingDate: '',
|
||||
proofreadingId: '',
|
||||
stage: '',
|
||||
subprojectId: '',
|
||||
subprojectName: '',
|
||||
verificationContent: '',
|
||||
verificationOpinion: '',
|
||||
volume: ''
|
||||
});
|
||||
// 时间 格式化 YYYY-MM-DD 改为 YYYY年MM月DD日
|
||||
const dateFormat = (v) => {
|
||||
if (!v) return '-';
|
||||
let time = new Date(v);
|
||||
let y = time.getFullYear();
|
||||
let MM = time.getMonth() + 1;
|
||||
MM = MM < 10 ? '0' + MM : MM;
|
||||
let d = time.getDate();
|
||||
d = d < 10 ? '0' + d : d;
|
||||
return y + '年' + MM + '月' + d + '日';
|
||||
};
|
||||
/** 查询设计-图纸评审列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listDrawingreview(queryParams.value);
|
||||
drawingreviewList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '添加设计-图纸评审';
|
||||
};
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initexamineForm };
|
||||
drawingreviewFormRef.value?.resetFields();
|
||||
};
|
||||
function handleUpdate(row) {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/drawingreview/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
}
|
||||
function handleViewInfo(row) {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/drawingreview/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
}
|
||||
const handleViewHistory = async (row) => {
|
||||
// 查看历史流程记录
|
||||
dialogHistory.value = true;
|
||||
let res = await ObtainHistoricalDesignDrawingsForReview(row.id);
|
||||
console.log(res);
|
||||
hisList.value = res;
|
||||
hisId.value = hisList.value[0].id;
|
||||
getDetails(hisId.value);
|
||||
};
|
||||
const handleShowInfo = (val) => {
|
||||
getDetails(val);
|
||||
};
|
||||
const getDetails = async (id) => {
|
||||
let res = await drawingreview(id);
|
||||
examineForm.value = res.data;
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
drawingreviewFormRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateDrawingreview(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addDrawingreview(form.value, fromData).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
// 上传excel
|
||||
function importExcel(options) {
|
||||
fromData.append('file', options.file);
|
||||
}
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.drawingreview {
|
||||
.upload-demo {
|
||||
width: 100% !important;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse; //合并为一个单一的边框
|
||||
border-color: rgba(199, 199, 199, 1); //边框颜色按实际自定义即可
|
||||
}
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
background-color: rgba(247, 247, 247, 1); //设置表格标题背景色
|
||||
height: 35px; //设置单元格最小高度
|
||||
text-align: center;
|
||||
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 {
|
||||
text-align: left;
|
||||
height: 40px; //设置单元格最小高度
|
||||
padding: 15px;
|
||||
}
|
||||
th {
|
||||
height: 35px; //设置单元格最小高度
|
||||
text-align: center;
|
||||
letter-spacing: 5px;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.table-content {
|
||||
box-shadow: 0px 0px 10px #ddd;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
341
src/views/design/drawingreview/indexEdit.vue
Normal file
341
src/views/design/drawingreview/indexEdit.vue
Normal file
@ -0,0 +1,341 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.design"
|
||||
:status="form.auditStatus"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">图纸评审</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
:disabled="routeParams.type === 'view' || form.auditStatus == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<el-form-item label="图纸文件" v-for="value in form.fileVoList" :key="value.id" prop="fileId" class="mb-2 md:col-span-2">
|
||||
<el-input v-model="value.fileName" disabled placeholder="图纸名称" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
import { getVolumeCatalog } from '@/api/design/volumeCatalog';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_designTheDiagram',
|
||||
label: '图纸评审'
|
||||
}
|
||||
];
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined,
|
||||
originalName: undefined,
|
||||
fileVoList: []
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
rules: {}
|
||||
});
|
||||
const onOpen = () => {
|
||||
window.open(form.value.path, '_blank');
|
||||
};
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getVolumeCatalog(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.design;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.design);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
// 图纸评审验证
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId, true, routeParams.value.businessId);
|
||||
};
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.auditStatus === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
console.log(routeParams.value.type);
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
234
src/views/design/prelimScheme/index.vue
Normal file
234
src/views/design/prelimScheme/index.vue
Normal file
@ -0,0 +1,234 @@
|
||||
<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="fileName">
|
||||
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:prelimScheme:list']">搜索</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">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:prelimScheme:add']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="schemeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName">
|
||||
<template #default="scope">
|
||||
<el-link type="primary" :href="scope.row.fileUrl" target="_blank" :underline="false">
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status !== 'draft'"
|
||||
icon="Edit"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['design:PrelimScheme:query']"
|
||||
>查看流程</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status === 'draft'"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['design:PrelimScheme:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
<!-- <el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status === 'draft'"
|
||||
icon="Delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['design:PrelimScheme: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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Scheme" lang="ts">
|
||||
import { listPrelimScheme, getPrelimScheme, delPrelimScheme, addPrelimScheme, updatePrelimScheme } from '@/api/design/prelimScheme';
|
||||
import { PrelimSchemeVO, PrelimSchemeQuery, PrelimSchemeForm } from '@/api/design/prelimScheme/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { useRoute } from 'vue-router';
|
||||
const route = useRoute();
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const schemeList = ref<PrelimSchemeVO[]>([]);
|
||||
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 schemeFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: PrelimSchemeForm = {
|
||||
id: undefined,
|
||||
projectId: undefined,
|
||||
ossId: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined
|
||||
};
|
||||
const data = reactive<PageData<PrelimSchemeForm, PrelimSchemeQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: undefined,
|
||||
ossId: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }],
|
||||
ossId: [{ required: true, message: 'ossId不能为空', trigger: 'blur' }],
|
||||
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
|
||||
status: [{ required: true, message: '审核状态不能为空', trigger: 'change' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询设计初步方案列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listPrelimScheme(queryParams.value);
|
||||
|
||||
schemeList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
schemeFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: PrelimSchemeVO[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
proxy.$tab.closePage(route);
|
||||
proxy.$tab.openPage('/approval/prelimScheme/indexEdit', '', {
|
||||
type: 'add'
|
||||
});
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: PrelimSchemeVO) => {
|
||||
proxy.$tab.closePage(route);
|
||||
|
||||
proxy.$tab.openPage(`/approval/prelimScheme/indexEdit`, '', {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: PrelimSchemeVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除设计初步方案编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delPrelimScheme(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleView = (row?: PrelimSchemeVO) => {
|
||||
proxy.$tab.closePage(route);
|
||||
proxy.$tab.openPage(`/approval/prelimScheme/indexEdit`, '', {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
423
src/views/design/prelimScheme/indexEdit.vue
Normal file
423
src/views/design/prelimScheme/indexEdit.vue
Normal file
@ -0,0 +1,423 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50 min-h-screen">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">设计初步方案信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="设计方案" prop="file" class="mb-2">
|
||||
<file-upload
|
||||
:limit="1"
|
||||
:fileType="['pdf']"
|
||||
:fileSize="100"
|
||||
v-model="form.file"
|
||||
ref="fileUploadRef"
|
||||
class="w-full"
|
||||
:auto-upload="false"
|
||||
:data="{ projectId: form.projectId }"
|
||||
:showFileList="showFileList"
|
||||
:onUploadSuccess="handleUploadSuccess"
|
||||
:uploadUrl="`${form.id ? '/design/prelimScheme/update/' + form.id : '/design/prelimScheme/upload'}`"
|
||||
@handleChange="handleFileChange"
|
||||
@handleRemove="handleFileRemove"
|
||||
></file-upload>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { getPrelimScheme, updatePrelimScheme } from '@/api/design/prelimScheme';
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
const showFileList = ref(true);
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
const fileUploadRef = ref<InstanceType<typeof fileUploadRef>>();
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_prelimScheme',
|
||||
label: '设计初步方案审批'
|
||||
}
|
||||
];
|
||||
const initFormData: any = {
|
||||
projectId: currentProject.value?.id,
|
||||
file: undefined
|
||||
};
|
||||
const data = reactive<any>({
|
||||
form: { ...initFormData },
|
||||
rules: {
|
||||
file: [
|
||||
{
|
||||
required: true,
|
||||
message: '请上传图纸文件',
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
const { form, rules } = toRefs(data);
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getPrelimScheme(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
form.value.file = res.data.ossId;
|
||||
showFileList.value = false;
|
||||
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = async (status1: string) => {
|
||||
status.value = status1;
|
||||
|
||||
var res;
|
||||
if (form.value.id) {
|
||||
if (!updateFileStatus.value) return proxy?.$modal.msgError('请上传图纸文件');
|
||||
buttonLoading.value = true;
|
||||
let data = { id: form.value.id, projectId: form.value.id, file: form.value.file };
|
||||
if (form.value.file === form.value.ossId) {
|
||||
data.file = '';
|
||||
res = await updatePrelimScheme(data).finally(() => (buttonLoading.value = false));
|
||||
|
||||
if (res.code == 200) {
|
||||
dialog.visible = false;
|
||||
submit(status.value, form.value);
|
||||
}
|
||||
} else {
|
||||
fileUploadRef.value.submitUpload();
|
||||
}
|
||||
} else {
|
||||
if (!fileStatus.value) {
|
||||
proxy?.$modal.msgError('请上传图纸文件');
|
||||
return;
|
||||
}
|
||||
buttonLoading.value = true;
|
||||
fileUploadRef.value.submitUpload();
|
||||
}
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(route);
|
||||
router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
console.log('🚀 ~ submit ~ status, data:', status, data);
|
||||
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
console.log(111);
|
||||
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(route);
|
||||
router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
console.log(221);
|
||||
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
console.log(data);
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
const handleUploadSuccess = (list, res) => {
|
||||
dialog.visible = false;
|
||||
if (form.value.id) {
|
||||
submit(status.value, form.value);
|
||||
} else {
|
||||
submit(status.value, { status: 'draft', id: res.data });
|
||||
}
|
||||
};
|
||||
|
||||
const fileStatus = ref(false);
|
||||
const updateFileStatus = ref(true);
|
||||
|
||||
const handleFileChange = (file, fileList) => {
|
||||
if (form.value.id) {
|
||||
updateFileStatus.value = true;
|
||||
}
|
||||
fileStatus.value = true;
|
||||
};
|
||||
|
||||
const handleFileRemove = (file, fileList) => {
|
||||
if (form.value.id) {
|
||||
updateFileStatus.value = false;
|
||||
}
|
||||
showFileList.value = true;
|
||||
|
||||
fileStatus.value = false;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
console.log(1111111111);
|
||||
routeParams.value = route.query;
|
||||
reset();
|
||||
console.log(routeParams.value);
|
||||
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
393
src/views/design/received/index.vue
Normal file
393
src/views/design/received/index.vue
Normal file
@ -0,0 +1,393 @@
|
||||
<template>
|
||||
<div class="p-6 bg-gray-50">
|
||||
<div class="appWidth mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
|
||||
<!-- 表单标题区域 -->
|
||||
<div class="bg-gradient-to-r from-blue-500 to-blue-600 text-white p-6">
|
||||
<h2 class="text-2xl font-bold flex items-center"><i class="el-icon-user-circle mr-3"></i>收集资料清单</h2>
|
||||
<p class="text-blue-100 mt-2 opacity-90">请填写相关资料信息</p>
|
||||
</div>
|
||||
|
||||
<!-- 表单内容区域 -->
|
||||
<el-form ref="mainFormRef" :model="form" :rules="mainRules" label-width="120px" class="p-6">
|
||||
<!-- 基本信息区域 -->
|
||||
<div class="bg-blue-50 p-4 rounded-lg mb-6">
|
||||
<h3 class="text-lg font-semibold text-blue-700 mb-4">基本信息</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="收资人" prop="userId" class="mb-4">
|
||||
<el-select
|
||||
:disabled="disabledAll"
|
||||
v-model="form.userId"
|
||||
placeholder="请选择收资人"
|
||||
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
|
||||
>
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业" prop="user_major" class="mb-4">
|
||||
<el-select
|
||||
:disabled="disabledAll"
|
||||
v-model="form.user_major"
|
||||
placeholder="请选择专业"
|
||||
class="transition-all duration-300 border-gray-300"
|
||||
:rules="{ required: true, message: '请选择专业', trigger: 'change' }"
|
||||
>
|
||||
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="电话" prop="phone" class="mb-4">
|
||||
<el-input :disabled="disabledAll" placeholder="请输入电话" v-model="form.phone" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="邮箱" prop="email" class="mb-4">
|
||||
<el-input :disabled="disabledAll" placeholder="请输入邮箱" v-model="form.email" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 资料文件区域 -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-blue-700">资料文件清单</h3>
|
||||
<el-button type="primary" size="small" @click="addDocumentItem" v-if="!disabledAll" icon="Plus"> 添加资料 </el-button>
|
||||
</div>
|
||||
<el-form ref="documentsFormRef" :model="form" class="space-y-4">
|
||||
<div v-for="(item, index) in form.documents" :key="item.id" class="bg-gray-50 p-4 rounded-lg transition-all duration-200 hover:shadow-sm">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<span class="text-sm font-medium text-gray-600">资料 {{ index + 1 }}</span>
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
text-color="#ff4d4f"
|
||||
@click="removeDocumentItem(index)"
|
||||
icon="el-icon-delete"
|
||||
v-if="form.documents.length > 1 && !disabledAll"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item
|
||||
label="文件目录名称"
|
||||
:prop="`documents.${index}.catalogueName`"
|
||||
:rules="[{ required: true, message: '请输入文件目录名称', trigger: 'blur' }]"
|
||||
class="mb-4"
|
||||
>
|
||||
<el-input :disabled="disabledAll" placeholder="请输入文件目录名称" v-model="item.catalogueName" autocomplete="off" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" :prop="`documents.${index}.remark`" class="mb-4">
|
||||
<el-input :disabled="disabledAll" placeholder="请输入备注" v-model="item.remark" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="flex justify-center gap-4 mt-8">
|
||||
<el-button type="primary" @click="submitForm" v-hasPermi="['design:collect:add']" v-if="!form.id || form.status == 'draft'" size="large"
|
||||
>确认提交</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="update"
|
||||
v-hasPermi="['design:collect:query']"
|
||||
v-show="form.id && form.status == 'draft'"
|
||||
icon="Edit"
|
||||
size="large"
|
||||
>审核</el-button
|
||||
>
|
||||
<el-button type="primary" @click="update" v-hasPermi="['design:collect:query']" v-show="form.status == 'back'" size="large" icon="Edit"
|
||||
>重新发起审核</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="onView"
|
||||
v-hasPermi="['design:collect:query']"
|
||||
v-show="form.id && form.status != 'draft'"
|
||||
icon="view"
|
||||
size="large"
|
||||
>查看流程</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
v-hasPermi="['design:collect:export']"
|
||||
@click="onLoad"
|
||||
v-show="form.id && form.status != 'draft'"
|
||||
icon="Download"
|
||||
size="large"
|
||||
>导出</el-button
|
||||
>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="DataCollectionForm" lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { ElMessage, ElLoading } from 'element-plus';
|
||||
import { systemUserList } from '@/api/design/appointment';
|
||||
import { collectBatch, byProjectId, exportWord } from '@/api/design/received';
|
||||
// 获取用户 store
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
|
||||
|
||||
// 表单引用
|
||||
const mainFormRef = ref();
|
||||
// 用户列表
|
||||
const userList = ref([]);
|
||||
const userMap = new Map();
|
||||
const disabledAll = ref(false);
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
projectId: currentProject.value?.id,
|
||||
userId: '', // 收资人
|
||||
user_major: '', // 专业
|
||||
phone: '', // 电话
|
||||
email: '', // 邮箱
|
||||
id: '',
|
||||
status: '',
|
||||
documents: [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '', // 文件目录名称
|
||||
remark: '' // 备注
|
||||
}
|
||||
] as Array<{
|
||||
id: number;
|
||||
catalogueName: string;
|
||||
remark: string;
|
||||
}>
|
||||
});
|
||||
|
||||
// 主表单验证规则
|
||||
const mainRules = reactive({
|
||||
userId: [{ required: true, message: '请输入收资人', trigger: 'blur' }],
|
||||
user_major: [{ required: true, message: '请选择专业', trigger: 'change' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
|
||||
]
|
||||
});
|
||||
|
||||
// 添加资料项
|
||||
const addDocumentItem = () => {
|
||||
form.documents.push({
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: ''
|
||||
});
|
||||
};
|
||||
|
||||
// 删除资料项
|
||||
const removeDocumentItem = (index: number) => {
|
||||
form.documents.splice(index, 1);
|
||||
};
|
||||
// 查询数据 再次回显
|
||||
const byProjectIdAll = async () => {
|
||||
// 调用接口获取数据
|
||||
const res = await byProjectId(currentProject.value?.id);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data;
|
||||
// 回显基本信息
|
||||
form.userId = data.userId || '';
|
||||
form.user_major = data.userMajor || '';
|
||||
form.phone = data.phone || '';
|
||||
form.email = data.email || '';
|
||||
form.id = data.id || '';
|
||||
form.status = data.status || '';
|
||||
if (form.status == 'finish') {
|
||||
// 表单全部禁用
|
||||
disabledAll.value = true;
|
||||
}
|
||||
// 回显资料文件列表
|
||||
if (data.catalogueList && data.catalogueList.length > 0) {
|
||||
// 清空现有列表
|
||||
form.documents = [];
|
||||
// 填充新数据
|
||||
data.catalogueList.forEach((item: any, index: number) => {
|
||||
form.documents.push({
|
||||
id: item.id || Date.now() + index, // 确保id唯一
|
||||
catalogueName: item.catalogueName || '',
|
||||
remark: item.remark || ''
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 如果没有资料,保持一个空项
|
||||
form.documents = [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
};
|
||||
// 提交表单
|
||||
const submitForm = async () => {
|
||||
if (!mainFormRef.value) return;
|
||||
try {
|
||||
const valid = await mainFormRef.value.validate();
|
||||
if (valid) {
|
||||
// 这里可以添加提交逻辑
|
||||
form.documents.map((item, i) => {
|
||||
item.num = i + 1;
|
||||
});
|
||||
let body = {
|
||||
desCollectBo: {
|
||||
projectId: currentProject.value?.id,
|
||||
userId: form.userId, // 收资人
|
||||
userMajor: form.user_major, // 专业
|
||||
id: form.id,
|
||||
phone: form.phone, // 电话
|
||||
email: form.email, // 邮箱
|
||||
userName: userMap.get(form.userId)
|
||||
},
|
||||
catalogueList: form.documents
|
||||
};
|
||||
let res = await collectBatch(body);
|
||||
if (res.code == 200) {
|
||||
byProjectIdAll();
|
||||
ElMessage.success('表单提交成功');
|
||||
} else {
|
||||
ElMessage.success(res.msg);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('请完善表单信息后再提交');
|
||||
}
|
||||
};
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
if (mainFormRef.value) {
|
||||
mainFormRef.value.resetFields();
|
||||
}
|
||||
// 重置资料列表,保留一个空项
|
||||
form.documents = [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: ''
|
||||
}
|
||||
];
|
||||
};
|
||||
/** 查询当前部门的所有用户 */
|
||||
const getDeptAllUser = async (deptId: any) => {
|
||||
try {
|
||||
const res = await systemUserList({ deptId });
|
||||
// 实际项目中使用接口返回的数据
|
||||
userList.value = res.rows;
|
||||
userList.value.forEach((user) => {
|
||||
userMap.set(user.userId, user.nickName);
|
||||
});
|
||||
} catch (error) {
|
||||
ElMessage.error('获取用户列表失败');
|
||||
}
|
||||
};
|
||||
const update = () => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/received/indexEdit`,
|
||||
query: {
|
||||
id: form.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
const onView = () => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/received/indexEdit`,
|
||||
query: {
|
||||
id: form.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
// 页面挂载时初始化数据
|
||||
onMounted(() => {
|
||||
// 可以在这里添加初始化逻辑
|
||||
getDeptAllUser(userStore.deptId).then(() => {
|
||||
byProjectIdAll();
|
||||
});
|
||||
});
|
||||
const onLoad = async () => {
|
||||
// 导出接口
|
||||
proxy?.download(
|
||||
'design/collect/exportWord',
|
||||
{
|
||||
id: form.id
|
||||
},
|
||||
`收资清单.zip`
|
||||
);
|
||||
};
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
getDeptAllUser(userStore.deptId).then(() => {
|
||||
byProjectIdAll();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.appWidth {
|
||||
width: 90%;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
// 全局样式调整,使界面更柔和
|
||||
::v-deep .el-input__inner,
|
||||
::v-deep .el-select__input {
|
||||
border-radius: 6px;
|
||||
border-color: #dcdfe6;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
::v-deep .el-input__inner:focus,
|
||||
::v-deep .el-select__input:focus {
|
||||
border-color: #409eff;
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
|
||||
::v-deep .el-button {
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item__label {
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
// 响应式调整
|
||||
@media (max-width: 768px) {
|
||||
.appWidth {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item__label {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
454
src/views/design/received/indexEdit.vue
Normal file
454
src/views/design/received/indexEdit.vue
Normal file
@ -0,0 +1,454 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">收集资料清单</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="appWidth mx-auto bg-white rounded-xl shadow-sm overflow-hidden transition-all duration-300 hover:shadow-md">
|
||||
<!-- 表单内容区域 -->
|
||||
<el-form ref="mainFormRef" :model="form" label-width="120px" class="p-6">
|
||||
<!-- 基本信息区域 -->
|
||||
<div class="bg-blue-50 p-4 rounded-lg mb-6">
|
||||
<h3 class="text-lg font-semibold text-blue-700 mb-4">基本信息</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="收资人" prop="userId" class="mb-4">
|
||||
<el-select
|
||||
disabled
|
||||
v-model="form.userId"
|
||||
placeholder="请选择收资人"
|
||||
class="w-full transition-all duration-300 border-gray-300 focus:border-blue-400 focus:ring-1 focus:ring-blue-400"
|
||||
>
|
||||
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业" prop="user_major" class="mb-4">
|
||||
<el-select
|
||||
disabled
|
||||
v-model="form.user_major"
|
||||
placeholder="请选择专业"
|
||||
class="transition-all duration-300 border-gray-300"
|
||||
:rules="{ required: true, message: '请选择专业', trigger: 'change' }"
|
||||
>
|
||||
<el-option v-for="item in des_user_major" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="电话" prop="phone" class="mb-4">
|
||||
<el-input disabled placeholder="请输入电话" v-model="form.phone" autocomplete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="邮箱" prop="email" class="mb-4">
|
||||
<el-input disabled placeholder="请输入邮箱" v-model="form.email" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 资料文件区域 -->
|
||||
<div class="mb-6">
|
||||
<el-form ref="documentsFormRef" :model="form" class="space-y-4">
|
||||
<div
|
||||
v-for="(item, index) in form.documents"
|
||||
:key="item.id"
|
||||
class="bg-gray-50 p-4 rounded-lg transition-all duration-200 hover:shadow-sm"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item
|
||||
label="文件目录名称"
|
||||
:prop="`documents.${index}.catalogueName`"
|
||||
:rules="[{ required: true, message: '请输入文件目录名称', trigger: 'blur' }]"
|
||||
class="mb-4"
|
||||
>
|
||||
<el-input disabled placeholder="请输入文件目录名称" v-model="item.catalogueName" autocomplete="off" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" :prop="`documents.${index}.remark`" class="mb-4">
|
||||
<el-input disabled placeholder="请输入备注" v-model="item.remark" autocomplete="off" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { systemUserList } from '@/api/design/appointment';
|
||||
import { collectBatch, byProjectId } from '@/api/design/received';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const { des_user_major } = toRefs<any>(proxy?.useDict('des_user_major'));
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_collect',
|
||||
label: '收资清单'
|
||||
}
|
||||
];
|
||||
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const approvalButtonRef = ref<InstanceType<typeof ApprovalButton>>();
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
// 用户列表
|
||||
const userList = ref([]);
|
||||
const userMap = new Map();
|
||||
// 表单引用
|
||||
const mainFormRef = ref();
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
projectId: currentProject.value?.id,
|
||||
userId: '', // 收资人
|
||||
user_major: '', // 专业
|
||||
phone: '', // 电话
|
||||
email: '', // 邮箱
|
||||
id: '',
|
||||
status: '',
|
||||
documents: [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '', // 文件目录名称
|
||||
remark: '' // 备注
|
||||
}
|
||||
] as Array<{
|
||||
id: number;
|
||||
catalogueName: string;
|
||||
remark: string;
|
||||
}>
|
||||
});
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
if (mainFormRef.value) {
|
||||
mainFormRef.value.resetFields();
|
||||
}
|
||||
// 重置资料列表,保留一个空项
|
||||
form.documents = [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: ''
|
||||
}
|
||||
];
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
buttonLoading.value = true;
|
||||
dialog.visible = false;
|
||||
submit(status.value, form);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
const submit = async (status, data) => {
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
/** 查询当前部门的所有用户 */
|
||||
const getDeptAllUser = async (deptId: any) => {
|
||||
try {
|
||||
const res = await systemUserList({ deptId });
|
||||
// 实际项目中使用接口返回的数据
|
||||
userList.value = res.rows;
|
||||
userList.value.forEach((user) => {
|
||||
userMap.set(user.userId, user.nickName);
|
||||
});
|
||||
} catch (error) {
|
||||
ElMessage.error('获取用户列表失败');
|
||||
}
|
||||
};
|
||||
// 查询数据 再次回显
|
||||
const byProjectIdAll = async () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
// 调用接口获取数据
|
||||
const res = await byProjectId(currentProject.value?.id);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data;
|
||||
// 回显基本信息
|
||||
form.userId = data.userId || '';
|
||||
form.user_major = data.userMajor || '';
|
||||
form.phone = data.phone || '';
|
||||
form.email = data.email || '';
|
||||
form.id = data.id || '';
|
||||
form.status = data.status || '';
|
||||
// 回显资料文件列表
|
||||
if (data.catalogueList && data.catalogueList.length > 0) {
|
||||
// 清空现有列表
|
||||
form.documents = [];
|
||||
// 填充新数据
|
||||
data.catalogueList.forEach((item: any, index: number) => {
|
||||
form.documents.push({
|
||||
id: item.id || Date.now() + index, // 确保id唯一
|
||||
catalogueName: item.catalogueName || '',
|
||||
remark: item.remark || ''
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 如果没有资料,保持一个空项
|
||||
form.documents = [
|
||||
{
|
||||
id: Date.now(),
|
||||
catalogueName: '',
|
||||
remark: ''
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getDeptAllUser(userStore.deptId).then(() => {
|
||||
byProjectIdAll();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
232
src/views/design/scheme/index.vue
Normal file
232
src/views/design/scheme/index.vue
Normal file
@ -0,0 +1,232 @@
|
||||
<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="fileName">
|
||||
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" v-hasPermi="['design:scheme:add']" @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">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:scheme:add']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="schemeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName">
|
||||
<template #default="scope">
|
||||
<el-link type="primary" :href="scope.row.fileUrl" target="_blank" :underline="false">
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status !== 'draft'"
|
||||
icon="Edit"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['design:PrelimScheme:query']"
|
||||
>查看流程</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status === 'draft'"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['design:scheme:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
<!-- <el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.status === 'draft'"
|
||||
icon="Delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['design:scheme: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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Scheme" lang="ts">
|
||||
import { listScheme, getScheme, delScheme, addScheme, updateScheme } from '@/api/design/scheme';
|
||||
import { SchemeVO, SchemeQuery, SchemeForm } from '@/api/design/scheme/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { useRoute } from 'vue-router';
|
||||
const route = useRoute();
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const schemeList = ref<SchemeVO[]>([]);
|
||||
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 schemeFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: SchemeForm = {
|
||||
id: undefined,
|
||||
projectId: undefined,
|
||||
ossId: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined
|
||||
};
|
||||
const data = reactive<PageData<SchemeForm, SchemeQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: undefined,
|
||||
ossId: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }],
|
||||
ossId: [{ required: true, message: 'ossId不能为空', trigger: 'blur' }],
|
||||
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
|
||||
status: [{ required: true, message: '审核状态不能为空', trigger: 'change' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询设计初步方案列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listScheme(queryParams.value);
|
||||
schemeList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
schemeFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: SchemeVO[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
proxy.$tab.closePage(route);
|
||||
proxy.$tab.openPage('/approval/scheme/indexEdit', '', {
|
||||
type: 'add'
|
||||
});
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: SchemeVO) => {
|
||||
proxy.$tab.closePage(route);
|
||||
|
||||
proxy.$tab.openPage(`/approval/scheme/indexEdit`, '', {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: SchemeVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除设计初步方案编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delScheme(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
};
|
||||
|
||||
const handleView = (row?: SchemeVO) => {
|
||||
proxy.$tab.closePage(route);
|
||||
proxy.$tab.openPage(`/approval/scheme/indexEdit`, '', {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
431
src/views/design/scheme/indexEdit.vue
Normal file
431
src/views/design/scheme/indexEdit.vue
Normal file
@ -0,0 +1,431 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50 min-h-screen">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">设计方案信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="设计方案" prop="fileUrl" class="mb-2">
|
||||
<file-upload
|
||||
:limit="1"
|
||||
:fileType="['pdf']"
|
||||
:fileSize="100"
|
||||
v-model="form.file"
|
||||
ref="fileUploadRef"
|
||||
class="w-full"
|
||||
:auto-upload="false"
|
||||
:data="{ projectId: currentProject.id }"
|
||||
:showFileList="showFileList"
|
||||
:onUploadSuccess="handleUploadSuccess"
|
||||
:uploadUrl="`${form.id ? '/design/scheme/update/' + form.id : '/design/scheme/upload'}`"
|
||||
@handleChange="handleFileChange"
|
||||
@handleRemove="handleFileRemove"
|
||||
></file-upload>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { DrawingForm } from '@/api/design/drawing/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getSpecialScheme, addSpecialScheme, updateSpecialScheme } from '@/api/design/specialScheme';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { getScheme, updateScheme } from '@/api/design/scheme';
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
const showFileList = ref(true);
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
const fileUploadRef = ref<InstanceType<typeof fileUploadRef>>();
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_completeScheme',
|
||||
label: '设计方案审批'
|
||||
}
|
||||
];
|
||||
const initFormData: any = {
|
||||
projectId: currentProject.value?.id,
|
||||
file: undefined
|
||||
};
|
||||
const data = reactive<any>({
|
||||
form: { ...initFormData },
|
||||
rules: {
|
||||
file: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 新增时必须上传文件
|
||||
if (!form.value.file) {
|
||||
callback(new Error('请上传图纸文件'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
const { form, rules } = toRefs(data);
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getScheme(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
form.value.file = res.data.ossId;
|
||||
showFileList.value = false;
|
||||
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = async (status1: string) => {
|
||||
status.value = status1;
|
||||
|
||||
var res;
|
||||
if (form.value.id) {
|
||||
if (!updateFileStatus.value) return proxy?.$modal.msgError('请上传图纸文件');
|
||||
buttonLoading.value = true;
|
||||
|
||||
let data = { id: form.value.id, projectId: form.value.id, file: form.value.file };
|
||||
if (form.value.file === form.value.ossId) {
|
||||
data.file = '';
|
||||
res = await updateScheme(data).finally(() => (buttonLoading.value = false));
|
||||
if (res.code == 200) {
|
||||
dialog.visible = false;
|
||||
submit(status.value, form.value);
|
||||
}
|
||||
} else {
|
||||
fileUploadRef.value.submitUpload();
|
||||
}
|
||||
} else {
|
||||
if (!fileStatus.value) {
|
||||
proxy?.$modal.msgError('请上传图纸文件');
|
||||
return;
|
||||
}
|
||||
buttonLoading.value = true;
|
||||
|
||||
fileUploadRef.value.submitUpload();
|
||||
}
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(route);
|
||||
router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
console.log('🚀 ~ submit ~ status, data:', status, data);
|
||||
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
console.log(111);
|
||||
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(route);
|
||||
router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
console.log(221);
|
||||
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
console.log(data);
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
const handleUploadSuccess = (list, res) => {
|
||||
dialog.visible = false;
|
||||
if (form.value.id) {
|
||||
submit(status.value, form.value);
|
||||
} else {
|
||||
submit(status.value, { status: 'draft', id: res.data });
|
||||
}
|
||||
};
|
||||
const fileStatus = ref(false);
|
||||
const updateFileStatus = ref(true);
|
||||
|
||||
const handleFileChange = (file, fileList) => {
|
||||
if (form.value.id) {
|
||||
updateFileStatus.value = true;
|
||||
}
|
||||
fileStatus.value = true;
|
||||
};
|
||||
|
||||
const handleFileRemove = (file, fileList) => {
|
||||
if (form.value.id) {
|
||||
updateFileStatus.value = false;
|
||||
}
|
||||
showFileList.value = true;
|
||||
|
||||
fileStatus.value = false;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
console.log(1111111111);
|
||||
routeParams.value = route.query;
|
||||
reset();
|
||||
console.log(routeParams.value);
|
||||
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
229
src/views/design/specialScheme/index.vue
Normal file
229
src/views/design/specialScheme/index.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<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="versionNumber">
|
||||
<el-input v-model="queryParams.versionNumber" placeholder="请输入版本号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="文件名称" prop="fileName">
|
||||
<el-input v-model="queryParams.fileName" placeholder="请输入文件名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="原文件名" prop="originalName">
|
||||
<el-input v-model="queryParams.originalName" placeholder="请输入原文件名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="审核状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择审核状态" clearable>
|
||||
<el-option v-for="dict in wf_business_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" v-hasPermi="['design:prelimScheme:query']" @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">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:specialScheme:add']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="specialSchemeList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="版本号" align="center" prop="versionNumber" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName">
|
||||
<template #default="scope">
|
||||
<span style="color: #409eff" @click="handleView(scope.row)">{{ scope.row.fileName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="原文件名" align="center" prop="originalName" />
|
||||
<el-table-column label="流程状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180"> </el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding">
|
||||
<template #default="scope">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
||||
<el-button v-hasPermi="['design:prelimScheme:edit']" size="small" type="primary" icon="Edit" @click="handleUpdate(scope.row)"
|
||||
>修改</el-button
|
||||
>
|
||||
</el-col>
|
||||
<!-- <el-col :span="1.5" v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'">
|
||||
<el-button v-hasPermi="['design:prelimScheme:remove']" size="small" type="primary" icon="Delete" @click="handleDelete(scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
v-hasPermi="['design:prelimScheme:query']"
|
||||
size="small"
|
||||
icon="View"
|
||||
v-if="scope.row.status != 'draft'"
|
||||
@click="handleViewInfo(scope.row)"
|
||||
>查看</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="scope.row.status === 'waiting'">
|
||||
<el-button size="small" type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.id)">撤销</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="SpecialScheme" lang="ts">
|
||||
import { listSpecialScheme, delSpecialScheme } from '@/api/design/specialScheme';
|
||||
import { SpecialSchemeVO } from '@/api/design/specialScheme/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { cancelProcessApply } from '@/api/workflow/instance';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const specialSchemeList = ref<SpecialSchemeVO[]>([]);
|
||||
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 data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
versionNumber: undefined,
|
||||
fileName: undefined,
|
||||
originalName: undefined,
|
||||
status: undefined,
|
||||
params: {}
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
/** 查询专项方案管理列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listSpecialScheme(queryParams.value);
|
||||
specialSchemeList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: SpecialSchemeVO[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/specialScheme/indexEdit`,
|
||||
query: {
|
||||
type: 'add'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: SpecialSchemeVO) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/specialScheme/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: SpecialSchemeVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除专项方案管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delSpecialScheme(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
};
|
||||
const handleView = (row) => {
|
||||
var url = row.file.url;
|
||||
window.open(url, '_blank');
|
||||
};
|
||||
/** 查看按钮操作 */
|
||||
const handleViewInfo = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/specialScheme/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 撤销按钮操作 */
|
||||
const handleCancelProcessApply = async (id: string) => {
|
||||
await proxy?.$modal.confirm('是否确认撤销当前单据?');
|
||||
loading.value = true;
|
||||
const data = {
|
||||
businessId: id,
|
||||
message: '申请人撤销流程!'
|
||||
};
|
||||
await cancelProcessApply(data).finally(() => (loading.value = false));
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('撤销成功');
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
397
src/views/design/specialScheme/indexEdit.vue
Normal file
397
src/views/design/specialScheme/indexEdit.vue
Normal file
@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50 min-h-screen">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">专项方案信息</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="120px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<el-form-item label="版本号" prop="versionNumber" class="mb-2">
|
||||
<el-input v-model="form.versionNumber" placeholder="请输入版本号" class="w-full"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="文件名称" prop="fileName" class="mb-2">
|
||||
<el-input v-model="form.fileName" placeholder="请输入文件名称" class="w-full"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="专项方案" prop="fileUrl" class="mb-2">
|
||||
<file-upload :limit="1" :fileType="['pdf']" :fileSize="100" v-model="form.fileUrl" class="w-full"></file-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark" class="mb-2 md:col-span-2">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" :rows="4" class="w-full"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { DrawingForm } from '@/api/design/drawing/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { getSpecialScheme, addSpecialScheme, updateSpecialScheme } from '@/api/design/specialScheme';
|
||||
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_specialScheme',
|
||||
label: '专项方案审批'
|
||||
}
|
||||
];
|
||||
const initFormData: DrawingForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
versionNumber: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
originalName: undefined,
|
||||
remark: undefined,
|
||||
file: undefined
|
||||
};
|
||||
const data = reactive<PageData<LeaveForm, LeaveQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
fileName: undefined,
|
||||
fileType: undefined,
|
||||
fileSuffix: undefined,
|
||||
fileStatus: undefined,
|
||||
originalName: undefined,
|
||||
newest: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
versionNumber: [{ required: true, message: '版本号不能为空', trigger: 'blur' }],
|
||||
fileName: [{ required: true, message: '文件名称不能为空', trigger: 'blur' }],
|
||||
fileType: [{ required: true, message: '文件类型不能为空', trigger: 'change' }],
|
||||
fileUrl: [
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 新增时必须上传文件
|
||||
if (!form.value.fileUrl) {
|
||||
callback(new Error('请上传图纸文件'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getSpecialScheme(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
leaveFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
var res;
|
||||
if (form.value.id) {
|
||||
res = await updateSpecialScheme(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
res = await addSpecialScheme(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
if (res.code == 200) {
|
||||
dialog.visible = false;
|
||||
submit(status.value, res.data);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
console.log(data);
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
console.log(1111111111);
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
console.log(routeParams.value);
|
||||
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
220
src/views/design/subcontract/index.vue
Normal file
220
src/views/design/subcontract/index.vue
Normal file
@ -0,0 +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="subContent">
|
||||
<el-input v-model="queryParams.subContent" placeholder="请输入分包内容" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:subcontract:add']">搜索</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">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['design:subcontract:add']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="subcontractList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" type="index" width="50" />
|
||||
<el-table-column label="分包内容" align="center" prop="subContent" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:subcontract:edit']">修改</el-button>
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['design:subcontract: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>
|
||||
<!-- 添加或修改设计分包对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form ref="subcontractFormRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="分包内容" prop="subContent">
|
||||
<el-input v-model="form.subContent" type="textarea" placeholder="请输入分包内容" clearable></el-input>
|
||||
</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="Subcontract" lang="ts">
|
||||
import { listSubcontract, getSubcontract, delSubcontract, addSubcontract, updateSubcontract } from '@/api/design/subcontract';
|
||||
import { SubcontractVO, SubcontractQuery, SubcontractForm } from '@/api/design/subcontract/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const subcontractList = ref<SubcontractVO[]>([]);
|
||||
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 subcontractFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: SubcontractForm = {
|
||||
id: undefined,
|
||||
projectId: currentProject.value?.id,
|
||||
subContent: undefined
|
||||
};
|
||||
const data = reactive<PageData<SubcontractForm, SubcontractQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
subContent: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目id不能为空', trigger: 'blur' }],
|
||||
subContent: [{ required: true, message: '分包内容不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询设计分包列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listSubcontract(queryParams.value);
|
||||
subcontractList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
subcontractFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: SubcontractVO[]) => {
|
||||
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?: SubcontractVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await getSubcontract(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改设计分包';
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
subcontractFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateSubcontract(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addSubcontract(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: SubcontractVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除设计分包编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delSubcontract(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'design/subcontract/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`subcontract_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
137
src/views/design/technicalStandard/component/bookFile.vue
Normal file
137
src/views/design/technicalStandard/component/bookFile.vue
Normal file
@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div class="book_file">
|
||||
<!-- 添加或修改公司对话框 -->
|
||||
<el-dialog v-model="isShowDialog" width="80vw" custom-class="book_file_loading" :close-on-click-modal="false" :destroy-on-close="true">
|
||||
<template #header>
|
||||
<div>查看资料文件</div>
|
||||
</template>
|
||||
<el-form ref="queryRef" :inline="true" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="8" class="colBlock">
|
||||
<el-form-item label="文件名称" prop="fileName">
|
||||
<el-input v-model="formData.fileName" placeholder="请输入文件名称搜索" clearable @keyup.enter.native="getDataFileQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getDataFileQuery">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
<el-button @click="resetQuery" type="danger">
|
||||
<el-icon><Refresh /></el-icon>清空
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div class="content">
|
||||
<div class="left_box" :style="treeList.length ? 'width: 70%' : 'width: 100%'">
|
||||
<el-table v-loading="loading" :data="tableData" border height="63vh" :empty-text="emptyText">
|
||||
<el-table-column label="序号" align="center" type="index" width="80px" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName" min-width="100px" />
|
||||
<el-table-column label="文件类型" align="center" prop="fileSuffix" width="100px" />
|
||||
|
||||
<el-table-column label="文件路径" align="center" min-width="100px">
|
||||
<template #default="scope">
|
||||
<span>{{ filterfilenPath(scope.row.filePath) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding" width="250px" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="success" link @click="onExport(scope.row)">
|
||||
<el-icon><Download /></el-icon>下载
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="onBook(scope.row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination :total="total" v-model:page="formData.pageNum" v-model:limit="formData.pageSize" @pagination="getDataFileQuery" />
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { listKnowledgeDocument } from '@/api/design/technicalStandard';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
|
||||
const emit = defineEmits(['onExport', 'onExportView', 'onBook']);
|
||||
const stores = useUserStoreHook();
|
||||
const loading = ref(false);
|
||||
const tableData = ref<any[]>([]);
|
||||
const isShowDialog = ref(false);
|
||||
const formData = reactive({
|
||||
fileName: '',
|
||||
projectId: stores.selectedProject.id,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
const total = ref(0);
|
||||
const emptyText = ref('暂无数据');
|
||||
const treeList = ref<any[]>([]);
|
||||
|
||||
const openDialog = () => {
|
||||
isShowDialog.value = true;
|
||||
getDataFileQuery();
|
||||
emptyText.value = '请输入文件名称进行搜索!';
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
tableData.value = [];
|
||||
formData.fileName = '';
|
||||
treeList.value = [];
|
||||
emptyText.value = '暂无数据';
|
||||
};
|
||||
|
||||
const getDataFileQuery = () => {
|
||||
loading.value = true;
|
||||
emptyText.value = '数据加载中……';
|
||||
listKnowledgeDocument(formData).then((res: any) => {
|
||||
loading.value = false;
|
||||
tableData.value = [];
|
||||
if (res.code == 200 && res.rows?.length) {
|
||||
tableData.value = res.rows;
|
||||
total.value = res.total;
|
||||
} else {
|
||||
emptyText.value = '没有查询到数据,请重新输入搜索';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onBook = (row: any) => {
|
||||
emit('onBook', row);
|
||||
};
|
||||
|
||||
const onExport = (row: any) => {
|
||||
emit('onExportView', row);
|
||||
};
|
||||
|
||||
const resetQuery = () => {
|
||||
tableData.value = [];
|
||||
formData.fileName = '';
|
||||
loading.value = false;
|
||||
emptyText.value = '暂无数据';
|
||||
};
|
||||
|
||||
const filterfilenPath = (val: string): string => {
|
||||
return val.replace(/^.*?知识库\//, '知识库/');
|
||||
};
|
||||
|
||||
defineExpose({ openDialog });
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.book_file {
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
</style>
|
190
src/views/design/technicalStandard/component/documentsDeails.vue
Normal file
190
src/views/design/technicalStandard/component/documentsDeails.vue
Normal file
@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="document_detail" id="document_detail">
|
||||
<div class="move_pop" id="detial_pop">
|
||||
<!-- <span>{{ title }}</span> -->
|
||||
<div class="box">
|
||||
<img v-if="type == 2" src="../icon/suo.png" @click="onFull(1)" />
|
||||
<img v-else src="../icon/full.png" @click="onFull(2)" />
|
||||
<span class="close" @click="onClose">✖</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_app" id="box_app"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { setMove } from '@/utils/moveDiv';
|
||||
declare const CXO_API: any;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'index',
|
||||
setup(props, { emit }) {
|
||||
const { proxy } = <any>getCurrentInstance();
|
||||
const state = reactive({
|
||||
title: '',
|
||||
type: 2
|
||||
});
|
||||
onMounted(() => {
|
||||
setMove('detial_pop', 'document_detail');
|
||||
});
|
||||
// 打开弹窗
|
||||
const openDialog = (obj) => {
|
||||
state.title = obj.fileName;
|
||||
init(obj);
|
||||
};
|
||||
const onError = function (event) {
|
||||
//举例,强制保存后,判断文档内容是否保存成功
|
||||
if (event.data) {
|
||||
if (event.data.errorCode == 'forcesave') {
|
||||
var desc = event.data.errorDescription;
|
||||
desc = JSON.parse(desc);
|
||||
if (desc.error == 0) {
|
||||
//保存成功
|
||||
} else {
|
||||
//保存失败或异常
|
||||
}
|
||||
} else if (event.data.errorCode == 'setallcellvalue') {
|
||||
var desc = event.data.errorDescription;
|
||||
desc = JSON.parse(desc);
|
||||
if (desc.error == 0) {
|
||||
//填充成功
|
||||
} else if (desc.error == -1) {
|
||||
//当前文档正处于协同编辑中
|
||||
} else {
|
||||
//填充异常
|
||||
}
|
||||
} else if (event.data.errorCode == 'clearsheet') {
|
||||
var desc = event.data.errorDescription;
|
||||
desc = JSON.parse(desc);
|
||||
if (desc.error == 0) {
|
||||
//清除成功
|
||||
} else if (desc.error == -1) {
|
||||
//当前文档正处于协同编辑中
|
||||
} else {
|
||||
//清除异常
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const onDocumentReady = function () {
|
||||
// console.log('文档加载完成');
|
||||
};
|
||||
const init = (obj) => {
|
||||
let documentKey = obj.id.toString() + new Date().getTime();
|
||||
console.log('🚀 ~ init ~ url:', obj.fileUrl);
|
||||
let type = obj.fileSuffix;
|
||||
if (obj.fileSuffix.includes('.')) {
|
||||
type = obj.fileSuffix.substring(1);
|
||||
}
|
||||
let documentType = 'word'; // docx doc
|
||||
if (type == 'xlsx' || type == 'xls') {
|
||||
documentType = 'cell'; //电子表格
|
||||
} else if (type == 'ppt' || type == 'pptx') {
|
||||
documentType = 'slide'; //演示文档文件
|
||||
}
|
||||
new CXO_API.CXEditor('box_app', {
|
||||
document: {
|
||||
fileType: type,
|
||||
key: documentKey,
|
||||
title: obj.fileName,
|
||||
url: obj.fileUrl
|
||||
},
|
||||
documentType,
|
||||
editorConfig: {
|
||||
mode: 'view',
|
||||
callbackUrl: ''
|
||||
},
|
||||
height: '100%',
|
||||
events: {
|
||||
onDocumentReady: onDocumentReady,
|
||||
onError: onError
|
||||
},
|
||||
zoom: -1
|
||||
});
|
||||
};
|
||||
const onClose = () => {
|
||||
emit('onClose', false);
|
||||
};
|
||||
const onFull = (type) => {
|
||||
// 全屏
|
||||
let document_detail = document.getElementById('document_detail');
|
||||
state.type = type;
|
||||
if (type == 2) {
|
||||
document_detail.style.width = '100%';
|
||||
document_detail.style.height = '100%';
|
||||
} else {
|
||||
document_detail.style.width = '1200px';
|
||||
document_detail.style.height = '80vh';
|
||||
}
|
||||
};
|
||||
return {
|
||||
proxy,
|
||||
openDialog,
|
||||
onClose,
|
||||
onFull,
|
||||
...toRefs(state)
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.document_detail {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #9f9f9f;
|
||||
.box_app {
|
||||
// width: 1300px !important;
|
||||
// height: 80vh !important;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
.move_pop {
|
||||
width: 100%;
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// right: 0%;
|
||||
height: 24px;
|
||||
// background: linear-gradient(#2a5095, #213f7b, #111e48);
|
||||
background-color: #f4f5f6;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
> span {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.box {
|
||||
display: flex;
|
||||
width: 60px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
// height: 100%;
|
||||
align-items: center;
|
||||
img {
|
||||
width: 22px;
|
||||
margin-top: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.close {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
/* top: -8px; */
|
||||
color: #8d8d8d;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
//border: 2px solid #0ff;
|
||||
border-radius: 50%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
203
src/views/design/technicalStandard/component/documentsEdit.vue
Normal file
203
src/views/design/technicalStandard/component/documentsEdit.vue
Normal file
@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div class="document_detail_eidt" id="document_detail_eidt">
|
||||
<div class="move_pop" id="detial_edit">
|
||||
<!-- <span>{{ title }}</span> -->
|
||||
<div class="box">
|
||||
<img v-if="type == 2" src="../icon/full.png" @click="onFull(1)" />
|
||||
<img v-else src="../icon/suo.png" @click="onFull(2)" />
|
||||
<span class="close" @click="onClose">✖</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box_app" id="box_app_edit"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { toRefs, reactive, onMounted, ref, defineComponent, watch, getCurrentInstance } from 'vue';
|
||||
import { setMove } from '@/utils/moveDiv';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
|
||||
// Ensure CXO_API is available globally or import it if it's a module
|
||||
// Example for global usage (e.g., included via script tag in index.html):
|
||||
declare const CXO_API: any;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'index',
|
||||
setup(props, { emit }) {
|
||||
const stores = useUserStoreHook();
|
||||
const { proxy } = <any>getCurrentInstance();
|
||||
const state = reactive({
|
||||
title: '',
|
||||
projectId: stores.selectedProject.id,
|
||||
type: 2,
|
||||
postUrl: ''
|
||||
});
|
||||
onMounted(() => {
|
||||
setMove('detial_edit', 'document_detail_eidt');
|
||||
});
|
||||
// 打开弹窗
|
||||
const openDialog = (obj, url) => {
|
||||
state.postUrl = url;
|
||||
|
||||
state.title = obj.name;
|
||||
init(obj);
|
||||
};
|
||||
const onError = function (event) {
|
||||
console.log('编辑器错误: code ' + event.data.errorCode + ', 描述' + event.data.errorDescription);
|
||||
//举例,强制保存后,判断文档内容是否保存成功
|
||||
if (event.data) {
|
||||
if (event.data.errorCode == 'forcesave') {
|
||||
var desc = event.data.errorDescription;
|
||||
desc = JSON.parse(desc);
|
||||
if (desc.error == 0) {
|
||||
//保存成功
|
||||
} else {
|
||||
//保存失败或异常
|
||||
}
|
||||
} else if (event.data.errorCode == 'setallcellvalue') {
|
||||
var desc = event.data.errorDescription;
|
||||
desc = JSON.parse(desc);
|
||||
if (desc.error == 0) {
|
||||
//填充成功
|
||||
} else if (desc.error == -1) {
|
||||
//当前文档正处于协同编辑中
|
||||
} else {
|
||||
//填充异常
|
||||
}
|
||||
} else if (event.data.errorCode == 'clearsheet') {
|
||||
var desc = event.data.errorDescription;
|
||||
desc = JSON.parse(desc);
|
||||
if (desc.error == 0) {
|
||||
//清除成功
|
||||
} else if (desc.error == -1) {
|
||||
//当前文档正处于协同编辑中
|
||||
} else {
|
||||
//清除异常
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const onDocumentReady = function () {
|
||||
console.log('文档加载完成');
|
||||
};
|
||||
const init = (obj) => {
|
||||
let documentKey = obj.id.toString() + new Date().getTime();
|
||||
let baseURL = import.meta.env.VITE_APP_BASE_API;
|
||||
let type = obj.fileSuffix;
|
||||
if (obj.fileSuffix.includes('.')) {
|
||||
type = obj.fileSuffix.substring(1);
|
||||
}
|
||||
let documentType = 'word'; // docx doc
|
||||
if (type == 'xlsx' || type == 'xls') {
|
||||
documentType = 'cell'; //电子表格
|
||||
} else if (type == 'ppt' || type == 'pptx') {
|
||||
documentType = 'slide'; //演示文档文件
|
||||
}
|
||||
console.log(baseURL + state.postUrl + '?path=' + obj.filePath + '&id=' + obj.id);
|
||||
new CXO_API.CXEditor('box_app_edit', {
|
||||
document: {
|
||||
fileType: obj.fileSuffix,
|
||||
key: documentKey,
|
||||
title: obj.fileName,
|
||||
url: obj.fileUrl
|
||||
},
|
||||
documentType,
|
||||
token: stores.token,
|
||||
editorConfig: {
|
||||
callbackUrl: baseURL + state.postUrl + obj.id + '?path=' + obj.filePath
|
||||
},
|
||||
events: {
|
||||
onDocumentReady: onDocumentReady,
|
||||
onError: onError
|
||||
}
|
||||
});
|
||||
};
|
||||
const onClose = () => {
|
||||
emit('onClose', false);
|
||||
};
|
||||
const onFull = (type) => {
|
||||
// 全屏
|
||||
let document_detail = document.getElementById('document_detail_eidt');
|
||||
state.type = type;
|
||||
if (type == 2) {
|
||||
// 弹框放大
|
||||
document_detail.style.width = '100%';
|
||||
document_detail.style.height = '100%';
|
||||
} else {
|
||||
// 弹框缩小
|
||||
document_detail.style.width = '1200px';
|
||||
document_detail.style.height = '80vh';
|
||||
}
|
||||
};
|
||||
return {
|
||||
proxy,
|
||||
onFull,
|
||||
openDialog,
|
||||
onClose,
|
||||
...toRefs(state)
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.document_detail_eidt {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #9f9f9f;
|
||||
.box_app {
|
||||
width: 1200px !important;
|
||||
height: 80vh !important;
|
||||
background-color: #f1f1f1;
|
||||
margin-top: 100px;
|
||||
}
|
||||
.move_pop {
|
||||
width: 100%;
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// right: 0%;
|
||||
height: 24px;
|
||||
// background: linear-gradient(#2a5095, #213f7b, #111e48);
|
||||
background-color: #f4f5f6;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
> span {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.box {
|
||||
display: flex;
|
||||
width: 60px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
// height: 100%;
|
||||
align-items: center;
|
||||
img {
|
||||
width: 22px;
|
||||
margin-top: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.close {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
/* top: -8px; */
|
||||
color: #8d8d8d;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
//border: 2px solid #0ff;
|
||||
border-radius: 50%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="system-document-container">
|
||||
<el-card shadow="hover">
|
||||
<div class="system-document-search mb-5">
|
||||
<el-form :model="param" ref="queryRef" :inline="true" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="2">
|
||||
<el-button type="success" :disabled="multiple" @click="onRecyclingStation(null, true)">
|
||||
<el-icon><RefreshRight /></el-icon>批量恢复
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-button type="danger" :disabled="multiple" @click="onRecyclingStation(null, false)">
|
||||
<el-icon><DeleteFilled /></el-icon>批量删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="tableData" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" type="index" min-width="30px" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName" min-width="100px" />
|
||||
<el-table-column label="文件路径" align="center" min-width="100px">
|
||||
<template #default="scope">
|
||||
<span>{{ filterfilenPath(scope.row.filePath) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="删除时间" align="center" prop="createTime" min-width="100px" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding" min-width="80px" fixed="right">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-button type="success" link @click="onRecyclingStation(scope.row, true)">
|
||||
<el-icon><RefreshRight /></el-icon>恢复
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="param.pageNum" v-model:limit="param.pageSize" @pagination="getDocumentDataList" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, getCurrentInstance, computed } from 'vue';
|
||||
import { ElMessageBox, ElMessage, ElLoading } from 'element-plus';
|
||||
import { documentDataAllList, templateRecycleBin, dataRecyclingStation } from '@/api/design/technicalStandard';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const userStore = useUserStoreHook();
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
|
||||
const loading = ref(false);
|
||||
const queryRef = ref();
|
||||
const multiple = ref(true);
|
||||
|
||||
const ids = ref<string>('');
|
||||
const tableData = ref<any[]>([]);
|
||||
const param = reactive({
|
||||
type: 2,
|
||||
projectId: currentProject.value?.id,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
const total = ref(0);
|
||||
const value = ref('2');
|
||||
|
||||
const getDocumentDataList = () => {
|
||||
loading.value = true;
|
||||
tableData.value = [];
|
||||
value.value = '2';
|
||||
documentDataAllList(param).then((res: any) => {
|
||||
tableData.value = res.rows ?? [];
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
ids.value = selection.map((item) => item.id).join(',');
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
const onRecyclingStation = (row: any, flag: boolean) => {
|
||||
let type = 2;
|
||||
let selectedIds: string = '';
|
||||
let title = '删除';
|
||||
let msg = '你确定要删除所选文件或文件夹?';
|
||||
|
||||
if (row) {
|
||||
selectedIds = row.id;
|
||||
} else {
|
||||
selectedIds = ids.value;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
type = 1;
|
||||
title = '恢复';
|
||||
msg = '你确定要恢复所选文件或文件夹?';
|
||||
}
|
||||
ElMessageBox.confirm(msg, '提示', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
const loadingInstance = ElLoading.service({
|
||||
lock: true,
|
||||
text: `正在${title}中……`,
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
if (flag) {
|
||||
dataRecyclingStation(selectedIds).then((res) => {
|
||||
loadingInstance.close();
|
||||
if (res.code == 200) {
|
||||
getDocumentDataList();
|
||||
ElMessage.success('操作成功');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
templateRecycleBin(selectedIds).then((res) => {
|
||||
loadingInstance.close();
|
||||
if (res.code == 200) {
|
||||
getDocumentDataList();
|
||||
ElMessage.success('操作成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const filterfilenPath = (val: string): string => {
|
||||
return val.replace(/^.*?知识库\//, '知识库/');
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
getDocumentDataList
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.colBlock {
|
||||
display: block;
|
||||
}
|
||||
.colNone {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
BIN
src/views/design/technicalStandard/icon/full.png
Normal file
BIN
src/views/design/technicalStandard/icon/full.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
src/views/design/technicalStandard/icon/suo.png
Normal file
BIN
src/views/design/technicalStandard/icon/suo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
603
src/views/design/technicalStandard/index.vue
Normal file
603
src/views/design/technicalStandard/index.vue
Normal file
@ -0,0 +1,603 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="activeName" class="demo-tabs p5" @tab-click="handleCheckMian">
|
||||
<el-tab-pane label="资料" name="first">
|
||||
<div class="profile_engin">
|
||||
<div class="box_info">
|
||||
<div class="tree_left1" id="tree_left1">
|
||||
<div class="file_upload check_select">
|
||||
<div class="box_btn">
|
||||
<file-upload
|
||||
v-model="state.paramsQuery.file"
|
||||
:limit="100"
|
||||
:uploadUrl="uploadUrl"
|
||||
:params="uploadParams"
|
||||
:on-upload-success="uploadFile"
|
||||
:fileType="[]"
|
||||
>
|
||||
<el-button type="primary" style="float: left" :disabled="!state.parentPid">
|
||||
<el-icon size="small"><Plus /></el-icon>上传文件
|
||||
</el-button>
|
||||
</file-upload>
|
||||
</div>
|
||||
<el-button type="primary" :disabled="!state.parentPid" @click="onExport"
|
||||
><el-icon><Download /></el-icon>下载</el-button
|
||||
>
|
||||
<el-button type="primary" @click="onBook"
|
||||
><el-icon><View /></el-icon>查看全项目文件</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="file_upload check_select">
|
||||
<el-input class="input_left" v-model="filterText" size="small" placeholder="请输入文件名称" />
|
||||
</div>
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
highlight-current
|
||||
:default-expand-all="state.checked"
|
||||
:filter-node-method="filterFolder"
|
||||
:data="state.treeList"
|
||||
node-key="id"
|
||||
accordion
|
||||
:expand-on-click-node="false"
|
||||
@node-click="handleNodeClick"
|
||||
:current-node-key="state.selectedNodeId"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span class="custom-tree-node">
|
||||
<el-icon color="#f1a81a"><FolderOpened /></el-icon>
|
||||
<span>{{ node.label }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
<div class="resize-handle resize-handle-right right"></div>
|
||||
</div>
|
||||
<div class="list_right" id="list_right1">
|
||||
<div>
|
||||
<el-form :model="state.paramsQuery" ref="queryRef" :inline="true" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="7" class="colBlock">
|
||||
<el-form-item label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
v-model="state.paramsQuery.fileName"
|
||||
placeholder="请输入文件名称"
|
||||
clearable
|
||||
@keyup.enter.native="getdocumentDataList"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6" class="m-l10">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="searchInfo"
|
||||
><el-icon><Search /></el-icon>搜索</el-button
|
||||
>
|
||||
<el-button @click="resetQuery"
|
||||
><el-icon><Refresh /></el-icon>重置</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table v-loading="state.loading" :data="state.infoList" height="67vh" border>
|
||||
<el-table-column label="序号" align="center" type="index" min-width="50px" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName"></el-table-column>
|
||||
<el-table-column label="文件类型" align="center" prop="fileSuffix" width="100px" />
|
||||
<el-table-column label="流程状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传时间" align="center" prop="createTime"> </el-table-column>
|
||||
<el-table-column label="操作" align="center" width="300">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link @click="handleApproval(scope.row)"
|
||||
><el-icon><Plus /></el-icon>审批</el-button
|
||||
>
|
||||
<el-button type="primary" link @click="handleViewApproval(scope.row)"
|
||||
><el-icon><View /></el-icon>流程查看</el-button
|
||||
>
|
||||
<el-button type="primary" link @click="handleView(scope.row)" v-if="acceptType.includes(scope.row.fileSuffix)"
|
||||
><el-icon><View /></el-icon>查看</el-button
|
||||
>
|
||||
<el-button type="primary" v-if="state.wordType.includes(scope.row.fileSuffix)" link @click="updataView(scope.row)"
|
||||
><el-icon><EditPen /></el-icon>修改文件</el-button
|
||||
>
|
||||
<el-button type="primary" link @click="onExportView(scope.row)"
|
||||
><el-icon><Download /></el-icon>下载</el-button
|
||||
>
|
||||
<el-button type="success" link @click="updateName(scope.row)"
|
||||
><el-icon><EditPen /></el-icon>修改名称</el-button
|
||||
>
|
||||
<el-button type="danger" link @click="handleDelete(scope.row)"
|
||||
><el-icon><DeleteFilled /></el-icon>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
:total="state.total"
|
||||
v-model:page="state.paramsQuery.pageNum"
|
||||
v-model:limit="state.paramsQuery.pageSize"
|
||||
@pagination="getdocumentDataList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<documentsDeailsVue ref="documentDetailRef" v-if="state.showDocumentDetail" @onClose="onClose"></documentsDeailsVue>
|
||||
<documentsEdit ref="documentDataEditRef" v-if="state.showdocumentDataEdit" @onClose="onCloseEdit"></documentsEdit>
|
||||
<bookFile ref="bookFileRef" @onExportView="onExportView" @onBook="handleView" @onExport="onExport"></bookFile>
|
||||
<el-dialog draggable title="上传文件" v-model="uploadFileder" width="30%">
|
||||
<file-upload v-model="state.paramsQuery.file"></file-upload>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button @click="uploadFileder = false">取消</el-button>
|
||||
<el-button type="primary" @click="subMitUpload">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<el-image-viewer
|
||||
ref="imageRef"
|
||||
style="width: 100%; height: 100%"
|
||||
:url-list="[imgUrl]"
|
||||
v-if="imgUrl"
|
||||
show-progress
|
||||
fit="cover"
|
||||
@close="imgUrl = ''"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="回收站" name="second">
|
||||
<RecyclingStation ref="recylingRef"></RecyclingStation>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="KnowledgeDocument" lang="ts">
|
||||
import {
|
||||
listKnowledgeDocument,
|
||||
delKnowledgeDocument,
|
||||
addKnowledgeDocument,
|
||||
getUniFolderDownloadList,
|
||||
treeStructureData,
|
||||
documentDataEdit
|
||||
} from '@/api/design/technicalStandard';
|
||||
|
||||
import documentsEdit from './component/documentsEdit.vue';
|
||||
import documentsDeailsVue from './component/documentsDeails.vue';
|
||||
import RecyclingStation from './component/recyclingStation.vue';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import bookFile from './component/bookFile.vue';
|
||||
const activeName = ref('first');
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
||||
const uploadUrl = computed(() => {
|
||||
return `/design/technicalStandard/file`;
|
||||
});
|
||||
const uploadParams = computed(() => {
|
||||
return {
|
||||
pid: state.paramsQuery.folderId,
|
||||
projectId: state.projectId
|
||||
};
|
||||
});
|
||||
const imgUrl = ref<string>('');
|
||||
const filterText = ref('');
|
||||
const treeRef = ref();
|
||||
const documentDetailRef = ref();
|
||||
const documentDataEditRef = ref();
|
||||
const uploadFileder = ref(false);
|
||||
const imageRef = ref();
|
||||
const recylingRef = ref();
|
||||
const bookFileRef = ref();
|
||||
const state = reactive({
|
||||
treeList: [] as any,
|
||||
arrayList: [] as any,
|
||||
infoMap: new Map(),
|
||||
infoList: [] as any,
|
||||
total: 0,
|
||||
paramsQuery: {
|
||||
folderId: '',
|
||||
fileName: '',
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
projectId: currentProject.value?.id,
|
||||
file: null,
|
||||
pid: null
|
||||
},
|
||||
loading: false,
|
||||
checked: true,
|
||||
showDocumentDetail: false,
|
||||
showdocumentDataEdit: false,
|
||||
showUploadFileder: false,
|
||||
parentRow: null,
|
||||
parentPid: null,
|
||||
parentName: '',
|
||||
selectedNodeId: null,
|
||||
projectId: currentProject.value?.id || '',
|
||||
imgType: ['jpg', 'png', 'jpeg', 'gif', 'svg'],
|
||||
wordType: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'],
|
||||
browserViewableType: ['html', 'htm', 'txt', 'log', 'md', 'json', 'xml', 'css', 'js'],
|
||||
|
||||
draggableCheck: true
|
||||
});
|
||||
|
||||
const acceptType = computed(() => [...state.imgType, ...state.wordType, ...state.browserViewableType]);
|
||||
|
||||
watch(filterText, (val: any) => {
|
||||
treeRef.value!.filter(val);
|
||||
});
|
||||
|
||||
// 上传文件
|
||||
const uploadFile = (files: any[]) => {
|
||||
proxy.$modal.success('上传成功');
|
||||
state.paramsQuery.file = null;
|
||||
getdocumentDataList();
|
||||
// uploadFileder.value = true;
|
||||
};
|
||||
|
||||
// 提交上传文件
|
||||
const subMitUpload = () => {
|
||||
if (!state.paramsQuery.file) {
|
||||
ElMessage.warning('请选择文件!');
|
||||
return;
|
||||
}
|
||||
addKnowledgeDocument(state.paramsQuery, { projectId: state.projectId, pid: state.parentPid }).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('上传成功');
|
||||
uploadFileder.value = false;
|
||||
state.paramsQuery.file = null; //清空文件
|
||||
getdocumentDataList();
|
||||
} else {
|
||||
ElMessage.error(res.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const searchInfo = () => {
|
||||
// 搜索
|
||||
getdocumentDataList();
|
||||
};
|
||||
const resetQuery = () => {
|
||||
// 重置
|
||||
state.paramsQuery.fileName = '';
|
||||
getdocumentDataList();
|
||||
};
|
||||
// 获取树形结构文件夹目录
|
||||
const gettreeStructureData = () => {
|
||||
state.parentPid = null;
|
||||
activeName.value = 'first';
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '正在加载中……',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
target: '.tree_left1'
|
||||
});
|
||||
treeStructureData(state.projectId).then((res: any) => {
|
||||
loading.close();
|
||||
if (res.code == 200 && res.data && res.data.length) {
|
||||
state.selectedNodeId = '';
|
||||
state.treeList = res.data;
|
||||
state.paramsQuery.folderId = res.data[0].id;
|
||||
getdocumentDataList();
|
||||
// setInfo(res.data);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 处理数据
|
||||
const setInfo = (arr) => {
|
||||
arr.forEach((element) => {
|
||||
state.arrayList.push(element);
|
||||
state.infoMap.set(element.folderId, element.id);
|
||||
if (element.treeStructureDataRes && element.treeStructureDataRes.length) {
|
||||
setInfo(element.treeStructureDataRes);
|
||||
}
|
||||
});
|
||||
};
|
||||
// 选择目录文件
|
||||
const handleNodeClick = (row) => {
|
||||
state.parentRow = row;
|
||||
state.parentPid = row.parentId;
|
||||
console.log(row);
|
||||
state.parentName = row.label;
|
||||
state.paramsQuery.folderId = row.id;
|
||||
getdocumentDataList();
|
||||
if (row.id === state.selectedNodeId) {
|
||||
// 如果当前节点已经选中,则取消选中
|
||||
state.selectedNodeId = null;
|
||||
state.parentPid = null; //关闭父级选择的id
|
||||
state.parentRow = null; //获取父级对象
|
||||
state.parentName = ''; //获取父级对应的名称
|
||||
state.paramsQuery.folderId = ''; //
|
||||
} else {
|
||||
// 否则选中当前节点 重新赋值
|
||||
state.selectedNodeId = row.id;
|
||||
}
|
||||
};
|
||||
// 获取文档列表数据
|
||||
const getdocumentDataList = () => {
|
||||
if (!state.paramsQuery.folderId) {
|
||||
return;
|
||||
}
|
||||
state.loading = true;
|
||||
listKnowledgeDocument(state.paramsQuery).then((res: any) => {
|
||||
state.loading = false;
|
||||
if (res.code == 200) {
|
||||
state.infoList = res.rows;
|
||||
state.total = res.total;
|
||||
}
|
||||
});
|
||||
};
|
||||
// 查询tree树形结构数据
|
||||
const filterFolder = (value: string, data: any) => {
|
||||
if (!value) return true;
|
||||
return data.name.includes(value);
|
||||
};
|
||||
const handleDelete = (row) => {
|
||||
// 删除文档
|
||||
let msg = '你确定要删除所选文件?';
|
||||
delFile(msg, row, () => {
|
||||
getdocumentDataList();
|
||||
});
|
||||
};
|
||||
|
||||
//切换tab
|
||||
const handleCheckMian = (tab, event) => {
|
||||
activeName.value = tab.name;
|
||||
if (activeName.value === 'first') {
|
||||
gettreeStructureData();
|
||||
} else {
|
||||
// 回收站
|
||||
recylingRef.value.getDocumentDataList();
|
||||
}
|
||||
};
|
||||
|
||||
const onExportView = (row) => {
|
||||
console.log(row);
|
||||
proxy.$download.direct(row.fileUrl, row.originalName);
|
||||
};
|
||||
const updateName = (row) => {
|
||||
// 修改名称
|
||||
editName(row, '请输入文件名称', 1);
|
||||
};
|
||||
const handleView = (row) => {
|
||||
if (state.imgType.includes(row.fileSuffix)) {
|
||||
imgUrl.value = row.fileUrl;
|
||||
return;
|
||||
} else if (state.wordType.includes(row.fileSuffix)) {
|
||||
state.showDocumentDetail = true;
|
||||
nextTick(() => {
|
||||
documentDetailRef.value.openDialog(row);
|
||||
});
|
||||
} else {
|
||||
window.open(row.fileUrl);
|
||||
}
|
||||
};
|
||||
// 关闭在线编辑弹框
|
||||
const onClose = () => {
|
||||
state.showDocumentDetail = false;
|
||||
};
|
||||
// 关闭修改的在线文档弹框
|
||||
const onCloseEdit = () => {
|
||||
state.showdocumentDataEdit = false;
|
||||
};
|
||||
const updataView = (row) => {
|
||||
// 修改文档
|
||||
state.showdocumentDataEdit = true;
|
||||
nextTick(() => {
|
||||
documentDataEditRef.value.openDialog(row, '/design/technicalStandard/changxie/callback/');
|
||||
});
|
||||
};
|
||||
// 删除文件及文件夹
|
||||
const delFile = (msg, data, cb) => {
|
||||
ElMessageBox.confirm(msg, '提示', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
delKnowledgeDocument([data.id]).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('删除成功');
|
||||
cb();
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
const editName = (data, title, type) => {
|
||||
ElMessageBox.prompt(title, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputErrorMessage: title,
|
||||
inputValue: data.fileName
|
||||
})
|
||||
.then(({ value }) => {
|
||||
documentDataEdit({ id: data.id, fileName: value }).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '修改成功'
|
||||
});
|
||||
// 数据重新刷新
|
||||
if (type == 2) {
|
||||
gettreeStructureData();
|
||||
} else {
|
||||
getdocumentDataList();
|
||||
}
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: res.message
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
const onExport = () => {
|
||||
getUniFolderDownloadList(state.paramsQuery.folderId).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
console.log(state.paramsQuery.fileName);
|
||||
proxy.$download.downloadFilesAsZip(res.data, { urlKey: 'fileUrl', nameKey: 'originalName', zipName: state.parentName + '.zip' });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 查看所有资料
|
||||
const onBook = () => {
|
||||
bookFileRef.value.openDialog();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
gettreeStructureData();
|
||||
});
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
state.projectId = nid;
|
||||
state.paramsQuery.projectId = nid;
|
||||
if (activeName.value === 'first') {
|
||||
gettreeStructureData();
|
||||
} else {
|
||||
// 回收站
|
||||
recylingRef.value.getDocumentDataList();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
const handleApproval = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/technicalStandard/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleViewApproval = (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/technicalStandard/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.profile_engin {
|
||||
height: 80vh;
|
||||
.set-tool {
|
||||
display: none;
|
||||
}
|
||||
.el-tree-node__content:hover,
|
||||
.el-tree-node__content:active {
|
||||
.set-tool {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
|
||||
background-color: #354e67 !important;
|
||||
color: #fff;
|
||||
}
|
||||
.box_info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.pagination-container {
|
||||
padding: 10px 0 !important;
|
||||
}
|
||||
> div {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.tree_left1 {
|
||||
width: 20%;
|
||||
background-color: #fff;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 6px;
|
||||
padding: 6px 0px;
|
||||
position: relative;
|
||||
min-width: 26%;
|
||||
border-right: 6px solid;
|
||||
border-right-color: rgba(204, 230, 255, 0);
|
||||
.resize-handle-right {
|
||||
top: 0;
|
||||
width: 6px;
|
||||
height: 100%;
|
||||
right: -10px;
|
||||
cursor: ew-resize;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
.check_select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
// justify-content: space-between;
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
.box_btn {
|
||||
margin: 0 10px 0 20px;
|
||||
position: relative;
|
||||
> span {
|
||||
padding: 4px 10px;
|
||||
background: #67c23a;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.btn {
|
||||
position: absolute;
|
||||
left: 20%;
|
||||
display: none;
|
||||
top: -2px;
|
||||
width: 220px;
|
||||
.el-button {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
.box_btn:hover,
|
||||
.box_btn:active {
|
||||
cursor: pointer;
|
||||
.btn {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.file_upload {
|
||||
margin: 2px 0;
|
||||
}
|
||||
.input_left {
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
// border-bottom: 1px solid #cbcbcb;
|
||||
}
|
||||
}
|
||||
.list_right {
|
||||
width: 79.5%;
|
||||
background: white;
|
||||
border: 1px solid #ededed;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.el-tree {
|
||||
height: calc(80vh - 160px);
|
||||
width: 100%;
|
||||
overflow: auto !important;
|
||||
}
|
||||
// .el-tree-node__children {
|
||||
// overflow: visible !important;
|
||||
// }
|
||||
}
|
||||
</style>
|
356
src/views/design/technicalStandard/indexEdit.vue
Normal file
356
src/views/design/technicalStandard/indexEdit.vue
Normal file
@ -0,0 +1,356 @@
|
||||
<template>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 顶部按钮区域 -->
|
||||
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
|
||||
<approvalButton
|
||||
@submitForm="submitForm"
|
||||
@approvalVerifyOpen="approvalVerifyOpen"
|
||||
@handleApprovalRecord="handleApprovalRecord"
|
||||
:buttonLoading="buttonLoading"
|
||||
:id="form.id"
|
||||
:status="form.status"
|
||||
:pageType="routeParams.type"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 表单区域 -->
|
||||
<el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
|
||||
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-800">设计原则</h3>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<el-form
|
||||
ref="leaveFormRef"
|
||||
v-loading="loading"
|
||||
:disabled="routeParams.type === 'view' || form.status == 'waiting'"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="文件名称" prop="formNo">
|
||||
<el-input disabled v-model="form.fileName" placeholder="请输入文件名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="文件" prop="formNo">
|
||||
<div style="display: flex">
|
||||
<span style="color: rgb(50, 142, 248)">{{ form.originalName }}</span>
|
||||
<!-- <el-button type="primary" link @click="handleView(scope.row)"
|
||||
><el-icon><View /></el-icon>查看</el-button
|
||||
> -->
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 提交组件 -->
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
||||
<approvalRecord ref="approvalRecordRef"></approvalRecord>
|
||||
<!-- 流程选择对话框 -->
|
||||
<el-dialog
|
||||
draggable
|
||||
v-model="dialogVisible.visible"
|
||||
:title="dialogVisible.title"
|
||||
:before-close="handleClose"
|
||||
width="500"
|
||||
class="rounded-lg shadow-lg"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-gray-600 mb-4">请选择要启动的流程:</p>
|
||||
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
|
||||
<el-option v-for="item in flowCodeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
|
||||
<el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
|
||||
>取消</el-button
|
||||
>
|
||||
<el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Leave" lang="ts">
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types';
|
||||
import { startWorkFlow } from '@/api/workflow/task';
|
||||
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
||||
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
||||
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
const { design_change_reason_type } = toRefs<any>(proxy?.useDict('design_change_reason_type'));
|
||||
import { getKnowledgeDocument } from '@/api/design/technicalStandard';
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
//路由参数
|
||||
const routeParams = ref<Record<string, any>>({});
|
||||
const flowCode = ref<string>('');
|
||||
const status = ref<string>('');
|
||||
const dialogVisible = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: '流程定义'
|
||||
});
|
||||
//提交组件
|
||||
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
||||
//审批记录组件
|
||||
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
||||
//按钮组件
|
||||
const flowCodeOptions = [
|
||||
{
|
||||
value: currentProject.value?.id + '_principletechnical',
|
||||
label: '设计原则审批'
|
||||
},
|
||||
{
|
||||
value: currentProject.value?.id + '_requirementstechnica',
|
||||
label: '业主需求清单审批'
|
||||
}
|
||||
];
|
||||
|
||||
const leaveFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
title: '',
|
||||
isEdit: false
|
||||
});
|
||||
const submitFormData = ref<StartProcessBo>({
|
||||
businessId: '',
|
||||
flowCode: '',
|
||||
variables: {}
|
||||
});
|
||||
const taskVariables = ref<Record<string, any>>({});
|
||||
|
||||
const initFormData = {
|
||||
id: undefined,
|
||||
fileName: undefined,
|
||||
fileUrl: undefined,
|
||||
status: undefined,
|
||||
originalName: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.visible = false;
|
||||
flowCode.value = '';
|
||||
buttonLoading.value = false;
|
||||
};
|
||||
const { form, rules } = toRefs(data);
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
leaveFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 获取详情 */
|
||||
const getInfo = () => {
|
||||
loading.value = true;
|
||||
buttonLoading.value = false;
|
||||
nextTick(async () => {
|
||||
const res = await getKnowledgeDocument(routeParams.value.id);
|
||||
Object.assign(form.value, res.data);
|
||||
loading.value = false;
|
||||
buttonLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = (status1: string) => {
|
||||
status.value = status1;
|
||||
submit(status.value, form.value);
|
||||
};
|
||||
|
||||
const submitFlow = async () => {
|
||||
handleStartWorkFlow(form.value);
|
||||
dialogVisible.visible = false;
|
||||
};
|
||||
//提交申请
|
||||
const handleStartWorkFlow = async (data: LeaveForm) => {
|
||||
try {
|
||||
submitFormData.value.flowCode = flowCode.value;
|
||||
submitFormData.value.businessId = data.id;
|
||||
//流程变量
|
||||
taskVariables.value = {
|
||||
// leave4/5 使用的流程变量
|
||||
userList: ['1', '3', '4']
|
||||
};
|
||||
submitFormData.value.variables = taskVariables.value;
|
||||
const resp = await startWorkFlow(submitFormData.value);
|
||||
if (submitVerifyRef.value) {
|
||||
buttonLoading.value = false;
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId);
|
||||
}
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
//审批记录
|
||||
const handleApprovalRecord = () => {
|
||||
approvalRecordRef.value.init(form.value.id);
|
||||
};
|
||||
//提交回调
|
||||
const submitCallback = async () => {
|
||||
await proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
};
|
||||
//审批
|
||||
const approvalVerifyOpen = async () => {
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
||||
};
|
||||
// 图纸上传成功之后 开始提交
|
||||
const submit = async (status, data) => {
|
||||
form.value = data;
|
||||
if (status === 'draft') {
|
||||
buttonLoading.value = false;
|
||||
proxy?.$modal.msgSuccess('暂存成功');
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.go(-1);
|
||||
} else {
|
||||
if ((form.value.status === 'draft' && (flowCode.value === '' || flowCode.value === null)) || routeParams.value.type === 'add') {
|
||||
flowCode.value = flowCodeOptions[0].value;
|
||||
dialogVisible.visible = true;
|
||||
return;
|
||||
}
|
||||
//说明启动过先随意穿个参数
|
||||
if (flowCode.value === '' || flowCode.value === null) {
|
||||
flowCode.value = 'xx';
|
||||
}
|
||||
await handleStartWorkFlow(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
routeParams.value = proxy.$route.query;
|
||||
reset();
|
||||
loading.value = false;
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
|
||||
getInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
:root {
|
||||
--primary: #409eff;
|
||||
--primary-light: #66b1ff;
|
||||
--primary-dark: #3a8ee6;
|
||||
--success: #67c23a;
|
||||
--warning: #e6a23c;
|
||||
--danger: #f56c6c;
|
||||
--info: #909399;
|
||||
}
|
||||
|
||||
/* 表单样式优化 */
|
||||
.el-form-item {
|
||||
.el-form-item__label {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-input__inner,
|
||||
.el-select .el-input__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.el-textarea__inner {
|
||||
border-radius: 4px;
|
||||
transition:
|
||||
border-color 0.2s,
|
||||
box-shadow 0.2s;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
.el-button {
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.is-primary {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-light);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--primary-dark);
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
color: var(--primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--primary-light);
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
.el-card {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
/* transform: translateY(-2px); */
|
||||
}
|
||||
}
|
||||
|
||||
/* 对话框样式优化 */
|
||||
.el-dialog {
|
||||
.el-dialog__header {
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
76
src/views/design/volumeCatalog/comm/TableContent.vue
Normal file
76
src/views/design/volumeCatalog/comm/TableContent.vue
Normal file
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<el-table :data="data" style="width: 100%" border>
|
||||
<!-- 文件名称列 -->
|
||||
<el-table-column prop="fileName" label="文件" align="center">
|
||||
<template #default="scope">
|
||||
<el-link
|
||||
:key="scope.row.fileId"
|
||||
:href="scope.row.fileUrl"
|
||||
target="_blank"
|
||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||
:underline="false"
|
||||
>
|
||||
{{ scope.row.fileName }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 版本号列 -->
|
||||
<el-table-column prop="size" label="版本号" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.version }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 审核状态列 -->
|
||||
<el-table-column label="审核状态" align="center" prop="auditStatus">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wfBusinessStatus" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作列 - 通过slot接收不同标签页的操作按钮 -->
|
||||
<el-table-column label="操作" width="170" align="center">
|
||||
<template #default="scope">
|
||||
<slot name="operation" :row="scope.row"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
// 获取子组件传入的prop
|
||||
// 定义文件数据类型
|
||||
interface FileItem {
|
||||
fileId: string | number;
|
||||
fileName: string;
|
||||
fileUrl: string;
|
||||
version: string;
|
||||
status: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义审核状态选项类型
|
||||
interface StatusOption {
|
||||
label: string;
|
||||
value: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 定义组件Props
|
||||
defineProps<{
|
||||
// 表格数据
|
||||
data: FileItem[];
|
||||
// 审核状态选项
|
||||
wfBusinessStatus: StatusOption[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 表格相关样式可以在这里定义 */
|
||||
::v-deep .el-table {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
253
src/views/design/volumeCatalog/comm/histroy.vue
Normal file
253
src/views/design/volumeCatalog/comm/histroy.vue
Normal file
@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<div class="volume-catalog-container">
|
||||
<div class="history-selector">
|
||||
<span>选择历史退回记录:</span>
|
||||
<el-select v-model="hisId" placeholder="请选择" style="width: 240px" @change="handleShowInfo">
|
||||
<el-option v-for="item in hisList" :key="item.id" :label="item.createTime" :value="item.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="volumeCatalog_box" style="margin-top: 20px">
|
||||
<!-- <span style="color: #0d9df5">查看excel文件</span> -->
|
||||
<div class="table-content" id="table-content" style="margin-top: 20px">
|
||||
<el-row class="mb20" style="display: flex; justify-content: center">
|
||||
<h2>设计验证表</h2>
|
||||
</el-row>
|
||||
|
||||
<el-row class="mb10" style="display: flex; justify-content: space-between">
|
||||
<div class="head-text">
|
||||
<span>编号:</span>
|
||||
<span>{{ examineForm.num }}</span>
|
||||
</div>
|
||||
<div class="head-text"></div>
|
||||
</el-row>
|
||||
|
||||
<table style="width: 100%" border="1" cellspacing="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">工程名称</th>
|
||||
<td class="th-bg" colspan="10">{{ examineForm.projectName }}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2">子项名称</th>
|
||||
<td class="th-bg" colspan="6">{{ examineForm.subprojectName }}</td>
|
||||
<th colspan="2">设计阶段</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.stage }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2">专业</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.professional }}</td>
|
||||
<th colspan="2">卷册</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.volume }}</td>
|
||||
<th colspan="2">设计人</th>
|
||||
<td class="th-bg" colspan="2">{{ examineForm.designer }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="2">验证内容</th>
|
||||
<td class="th-bg" colspan="10">{{ examineForm.verificationContent }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th colspan="6">验证意见</th>
|
||||
<th class="th-bg" colspan="6">执行意见</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div style="height: 400px; padding: 8px; box-sizing: border-box">
|
||||
{{ examineForm.verificationOpinion }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="th-bg" colspan="6">
|
||||
<div style="height: 400px; padding: 8px; box-sizing: border-box">
|
||||
{{ examineForm.executionOpinion }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; padding: 8px">
|
||||
<span>校审: {{ examineForm.proofreading }}</span>
|
||||
<span>{{ dateFormat(examineForm.proofreadingDate) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td rowspan="2" colspan="6" class="th-bg">
|
||||
<div style="padding: 8px">执行人: {{ examineForm.executor }}</div>
|
||||
<div style="display: flex; align-items: center; justify-content: flex-end; padding: 8px">
|
||||
{{ dateFormat(examineForm.executorDate) }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="th-bg" colspan="6">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; padding: 8px">
|
||||
<span>审核: {{ examineForm.audit }}</span>
|
||||
<span>{{ dateFormat(examineForm.auditDate) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="VolumeCatalog" lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { ElSelect, ElOption, ElRow } from 'element-plus';
|
||||
import { drawingreviewReceiptsDetail, drawingreviewReceiptsList } from '@/api/design/drawingreview';
|
||||
|
||||
// 定义历史记录项类型
|
||||
interface HistoryItem {
|
||||
id: string | number;
|
||||
createTime: string;
|
||||
}
|
||||
|
||||
// 定义表单数据类型
|
||||
interface ExamineForm {
|
||||
num: string;
|
||||
projectName: string;
|
||||
subprojectName: string;
|
||||
stage: string;
|
||||
professional: string;
|
||||
volume: string;
|
||||
designer: string;
|
||||
verificationContent: string;
|
||||
verificationOpinion: string;
|
||||
executionOpinion: string;
|
||||
proofreading: string;
|
||||
proofreadingDate: string | Date | null;
|
||||
executor: string;
|
||||
executorDate: string | Date | null;
|
||||
audit: string;
|
||||
auditDate: string | Date | null;
|
||||
}
|
||||
|
||||
// 响应式变量
|
||||
const hisId = ref<string | number>('');
|
||||
const hisList = ref<HistoryItem[]>([]);
|
||||
|
||||
const examineForm = reactive<ExamineForm>({
|
||||
num: '',
|
||||
projectName: '',
|
||||
subprojectName: '',
|
||||
stage: '',
|
||||
professional: '',
|
||||
volume: '',
|
||||
designer: '',
|
||||
verificationContent: '',
|
||||
verificationOpinion: '',
|
||||
executionOpinion: '',
|
||||
proofreading: '',
|
||||
proofreadingDate: null,
|
||||
executor: '',
|
||||
executorDate: null,
|
||||
audit: '',
|
||||
auditDate: null
|
||||
});
|
||||
|
||||
// 处理历史记录选择变化
|
||||
const handleShowInfo = async (value: string | number) => {
|
||||
getDetails(value);
|
||||
};
|
||||
|
||||
// 日期格式化方法
|
||||
const dateFormat = (date: string | Date | null): string => {
|
||||
if (!date) return '';
|
||||
|
||||
// 处理字符串类型的日期
|
||||
if (typeof date === 'string') {
|
||||
date = new Date(date);
|
||||
}
|
||||
|
||||
// 检查日期是否有效
|
||||
if (isNaN(date.getTime())) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
// 获取详情
|
||||
const getList = async (drawingreviewId) => {
|
||||
let res = await drawingreviewReceiptsList({ drawingreviewId });
|
||||
hisList.value = res.rows;
|
||||
if (hisList.value.length > 0) {
|
||||
hisId.value = hisList.value[0].id;
|
||||
getDetails(hisId.value);
|
||||
}
|
||||
};
|
||||
const getDetails = async (id) => {
|
||||
let res = await drawingreviewReceiptsDetail(id);
|
||||
Object.assign(examineForm, res.data);
|
||||
};
|
||||
// 抛出
|
||||
defineExpose({ getList });
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.volume-catalog-container {
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
table {
|
||||
border-collapse: collapse; //合并为一个单一的边框
|
||||
border-color: rgba(199, 199, 199, 1); //边框颜色按实际自定义即可
|
||||
}
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
background-color: rgba(247, 247, 247, 1); //设置表格标题背景色
|
||||
height: 35px; //设置单元格最小高度
|
||||
text-align: center;
|
||||
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 {
|
||||
text-align: left;
|
||||
height: 40px; //设置单元格最小高度
|
||||
padding: 15px;
|
||||
}
|
||||
th {
|
||||
height: 35px; //设置单元格最小高度
|
||||
text-align: center;
|
||||
letter-spacing: 5px;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.table-content {
|
||||
box-shadow: 0px 0px 10px #ddd;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
622
src/views/design/volumeCatalog/index.vue
Normal file
622
src/views/design/volumeCatalog/index.vue
Normal file
@ -0,0 +1,622 @@
|
||||
<template>
|
||||
<div class="p-2 volumeCatalog">
|
||||
<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="volumeNumber">
|
||||
<el-input v-model="queryParams.volumeNumber" placeholder="请输入卷册号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="资料名称" prop="documentName">
|
||||
<el-input v-model="queryParams.documentName" placeholder="请输入资料名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['design:volumeCatalog:query']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['design:volumeCatalog:query']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</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="['design:volumeCatalog:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<file-upload
|
||||
v-model="form.file"
|
||||
isImportInfo
|
||||
:isShowTip="false"
|
||||
uploadUrl="/design/volumeCatalog/importData"
|
||||
:limit="1"
|
||||
:fileType="['xlsx', 'xls']"
|
||||
:data="{
|
||||
projectId: currentProject?.id
|
||||
}"
|
||||
:file-size="50"
|
||||
:onUploadSuccess="handleUploadSuccess"
|
||||
>
|
||||
<el-button type="warning" plain icon="Upload">导入</el-button>
|
||||
</file-upload>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table v-loading="loading" :data="volumeCatalogList">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="子项名称" align="center" prop="designSubitem" />
|
||||
<el-table-column label="设计状态" align="center" prop="designState">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="design_state" :value="scope.row.designState" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="专业" align="center" prop="specialtyName"> </el-table-column>
|
||||
<el-table-column label="设计人员" align="center" prop="principalName" />
|
||||
<el-table-column label="卷册号" align="center" prop="volumeNumber" />
|
||||
<el-table-column label="资料名称" align="center" prop="documentName" />
|
||||
<el-table-column label="计划出图时间" align="center" prop="plannedCompletion" width="200" />
|
||||
<el-table-column label="审核状态" align="center" prop="auditStatus">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.auditStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传说明" align="center" prop="explainText">
|
||||
<template #default="scope">
|
||||
{{ scope.row.fileVoList[0]?.explainText }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="图纸文件" align="center" prop="remark" width="150">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['design:volumeFile:query']">查看文件</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" width="200">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
v-if="scope.row.auditStatus != 'finish' && scope.row.auditStatus != 'termination' && scope.row.auditStatus != 'waiting'"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['design:volumeFile:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Upload"
|
||||
@click="handleUpload(scope.row)"
|
||||
v-if="scope.row.auditStatus == 'draft' || scope.row.auditStatus == 'back'"
|
||||
v-hasPermi="['design:volumeFile:add']"
|
||||
>上传图纸</el-button
|
||||
>
|
||||
<!-- <el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="edit"
|
||||
@click="handleAudit(scope.row)"
|
||||
v-if="scope.row.auditStatus == 'draft' || scope.row.auditStatus == 'back'"
|
||||
>审核</el-button
|
||||
>
|
||||
<el-button link type="primary" icon="View" v-if="scope.row.auditStatus != 'draft'" @click="handleAuditView(scope.row)"
|
||||
>查看流程</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
link
|
||||
icon="View"
|
||||
v-if="scope.row.auditType == 'back' || scope.row.auditStatus == 'termination'"
|
||||
@click="handleViewHistory(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="getList" />
|
||||
</el-card>
|
||||
<!-- 添加或修改卷册目录对话框 -->
|
||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form ref="volumeCatalogFormRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="子项" prop="designSubitem">
|
||||
<el-input v-model="form.designSubitem" placeholder="请输入设计子项" />
|
||||
</el-form-item>
|
||||
<el-form-item label="专业" prop="specialty">
|
||||
<el-select v-model="form.specialty" placeholder="请选择专业">
|
||||
<el-option :value="item.value" v-for="item in des_user_major" :key="item.value" :label="item.label" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="设计人员" prop="principal">
|
||||
<el-select v-model="form.principal" placeholder="请选择设计人员" class="transition-all duration-300 border-gray-300">
|
||||
<el-option v-for="item in userAppList" :key="item.userId" :label="item.userName" :value="item.userId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="设计状态" prop="designState">
|
||||
<el-select v-model="form.designState" placeholder="请选择设计状态">
|
||||
<el-option :value="item.value" v-for="item in design_state" :key="item.value" :label="item.label" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="计划出图时间" prop="plannedCompletion">
|
||||
<el-date-picker v-model="form.plannedCompletion" type="date" value-format="YYYY-MM-DD" placeholder="请选择计划出图时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="卷册号" prop="volumeNumber">
|
||||
<el-input v-model="form.volumeNumber" placeholder="请输入卷册号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="资料名称" prop="documentName">
|
||||
<el-input v-model="form.documentName" 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>
|
||||
<el-dialog draggable title="上传图纸文件" v-model="uploadVisible" width="500px" append-to-body>
|
||||
<el-form :model="uploadForm" label-width="80px" :inline="false">
|
||||
<el-form-item label="蓝图" prop="type">
|
||||
<el-select v-model="uploadForm.type" placeholder="请选择图纸类型"
|
||||
><el-option label="过程图纸" value="1" /><el-option label="蓝图" value="3"
|
||||
/></el-select>
|
||||
</el-form-item>
|
||||
<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 == '1'" label="过程图纸" prop="cancellationIds">
|
||||
<file-upload :fileType="['pdf']" :isShowTip="false" :fileSize="100" v-model="uploadForm.cancellationIds"></file-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span style="font-size: 12px; color: #999999">注意:请上传pdf格式文件</span>
|
||||
<div style="display: flex; justify-content: flex-end">
|
||||
<el-button type="primary" @click="onSubmit" :loading="buttonLoading">确定</el-button>
|
||||
<el-button @click="uploadVisible = false">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 查看文件列表 -->
|
||||
<el-dialog draggable title="图纸列表" v-model="viewVisible" width="45%">
|
||||
<el-tabs type="border-card" v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="蓝图" name="first"
|
||||
><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.status == 'draft' || row.status == 'back'"
|
||||
>审核</el-button
|
||||
>
|
||||
<el-button link type="primary" icon="View" v-if="row.status != 'draft'" @click="handleAuditView(row)">查看流程</el-button>
|
||||
<el-button type="danger" link icon="Download" @click="handleDownload(row)"> 下载 </el-button>
|
||||
</template>
|
||||
</TableContent></el-tab-pane
|
||||
>
|
||||
<el-tab-pane label="过程图纸 " name="second"
|
||||
><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.status == 'draft' || row.status == 'back'"
|
||||
>审核</el-button
|
||||
>
|
||||
<el-button link type="primary" icon="View" v-if="row.status != 'draft'" @click="handleAuditView(row)">查看流程</el-button>
|
||||
<el-button type="danger" link icon="Download" @click="handleDownload(row)"> 下载 </el-button>
|
||||
</template>
|
||||
</TableContent></el-tab-pane
|
||||
>
|
||||
<el-tab-pane label="变更" name="third"
|
||||
><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
|
||||
>
|
||||
<el-tab-pane label="作废 " name="fourth"
|
||||
><TableContent :data="fileList" :wf-business-status="wf_business_status">
|
||||
<template #operation="{ row }">
|
||||
<el-button type="danger" link icon="Download" @click="handleDownload(row)"> 下载1 </el-button>
|
||||
</template>
|
||||
</TableContent></el-tab-pane
|
||||
>
|
||||
</el-tabs>
|
||||
<template #footer>
|
||||
<span>
|
||||
<el-button type="danger" @click="viewVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-dialog draggable title="单据" v-model="dialogHistory" width="800px">
|
||||
<histroy ref="histroyRef"></histroy>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="VolumeCatalog" lang="ts">
|
||||
import {
|
||||
listVolumeCatalog,
|
||||
getVolumeCatalog,
|
||||
delVolumeCatalog,
|
||||
addVolumeCatalog,
|
||||
updateVolumeCatalog,
|
||||
uploadVolumeFile,
|
||||
getVolumeCatafileList,
|
||||
lookViewerFile
|
||||
} from '@/api/design/volumeCatalog';
|
||||
import { VolumeCatalogVO } from '@/api/design/volumeCatalog/types';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import histroy from './comm/histroy.vue';
|
||||
import TableContent from './comm/tableContent.vue';
|
||||
const fileList = ref([]);
|
||||
import { designUserList } from '@/api/design/appointment';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { design_state, wf_business_status, des_user_major } = toRefs(proxy?.useDict('design_state', 'wf_business_status', 'des_user_major'));
|
||||
import { drawingreviewReceiptsDetail, drawingreviewReceiptsList } from '@/api/design/drawingreview';
|
||||
const volumeCatalogList = ref<VolumeCatalogVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const histroyRef = ref<InstanceType<typeof histroy>>();
|
||||
const TableContentRef = ref<InstanceType<typeof TableContentRef>>();
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const activeName = ref('first');
|
||||
const total = ref(0);
|
||||
const dialogHistory = ref(false);
|
||||
// 获取用户 store
|
||||
const userStore = useUserStoreHook();
|
||||
// 从 store 中获取项目列表和当前选中的项目
|
||||
const currentProject = computed(() => userStore.selectedProject);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const volumeCatalogFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const uploadForm = reactive({
|
||||
userIds: [],
|
||||
volumeCatalogId: undefined,
|
||||
fileIds: undefined,
|
||||
cancellationIds: undefined,
|
||||
explainText: '',
|
||||
fileList: [],
|
||||
type: '1',
|
||||
cancellationIds: [] // 用于存储已作废的文件ID
|
||||
});
|
||||
const examineForm = ref({
|
||||
audit: '',
|
||||
auditDate: '',
|
||||
auditId: '',
|
||||
designer: '',
|
||||
executionOpinion: '',
|
||||
executor: '',
|
||||
executorDate: '',
|
||||
executorId: '',
|
||||
id: '1',
|
||||
num: '',
|
||||
professional: '',
|
||||
projectId: '',
|
||||
projectName: '',
|
||||
proofreading: '',
|
||||
proofreadingDate: '',
|
||||
proofreadingId: '',
|
||||
stage: '',
|
||||
subprojectId: '',
|
||||
subprojectName: '',
|
||||
verificationContent: '',
|
||||
verificationOpinion: '',
|
||||
volume: ''
|
||||
});
|
||||
const userList = ref([]);
|
||||
const userAppList = ref([]); //人事任命的用户
|
||||
const initFormData: any = {
|
||||
design: undefined,
|
||||
projectId: currentProject.value?.id || '',
|
||||
designSubitemId: undefined,
|
||||
volumeNumber: undefined,
|
||||
documentName: undefined,
|
||||
designState: '2',
|
||||
|
||||
remark: undefined
|
||||
};
|
||||
const data = reactive({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectId: currentProject.value?.id,
|
||||
designSubitemId: undefined,
|
||||
volumeNumber: undefined,
|
||||
documentName: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {
|
||||
design: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||
volumeNumber: [{ required: true, message: '卷册号不能为空', trigger: 'blur' }],
|
||||
documentName: [{ required: true, message: '资料名称不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询卷册目录列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listVolumeCatalog(queryParams.value);
|
||||
volumeCatalogList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
const getUserAppList = async () => {
|
||||
const res = await designUserList({ projectId: currentProject.value?.id });
|
||||
if (res.code === 200) {
|
||||
console.log(res.rows);
|
||||
|
||||
res.rows.forEach((item: any) => {
|
||||
if (item.userType == 2) {
|
||||
//设计人员
|
||||
userAppList.value.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleViewHistory = async (row) => {
|
||||
// 查看历史流程记录
|
||||
dialogHistory.value = true;
|
||||
// 查看历史流程记录
|
||||
nextTick(() => {
|
||||
histroyRef.value?.getList(row.design);
|
||||
});
|
||||
};
|
||||
const handleShowInfo = (val) => {
|
||||
getDetails(val);
|
||||
};
|
||||
const getDetails = async (id) => {
|
||||
let res = await drawingreviewReceiptsDetail(id);
|
||||
examineForm.value = res.data;
|
||||
};
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
volumeCatalogFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: VolumeCatalogVO[]) => {
|
||||
ids.value = selection.map((item) => item.design);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = '添加设计出图计划';
|
||||
};
|
||||
|
||||
const handleView = (row?: any) => {
|
||||
fileList.value = row.fileVoList;
|
||||
|
||||
viewVisible.value = true;
|
||||
};
|
||||
|
||||
/** 上传文件按钮操作 */
|
||||
const uploadVisible = ref(false);
|
||||
const viewVisible = ref(false);
|
||||
const handleUpload = async (row?: any) => {
|
||||
resetUploadForm();
|
||||
uploadForm.volumeCatalogId = row.design;
|
||||
userList.value = row.noViewerList;
|
||||
const res = await getVolumeCatafileList(row.design);
|
||||
uploadForm.fileList = res.data.filter((item) => item.status == '1') || [];
|
||||
uploadVisible.value = true;
|
||||
};
|
||||
/** 重置上传表单 */
|
||||
const resetUploadForm = () => {
|
||||
uploadForm.userIds = [];
|
||||
uploadForm.volumeCatalogId = undefined;
|
||||
uploadForm.fileIds = undefined;
|
||||
uploadForm.cancellationIds = undefined;
|
||||
uploadForm.explainText = '';
|
||||
uploadForm.fileList = [];
|
||||
uploadForm.type = '1';
|
||||
uploadForm.cancellationIds = [];
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
volumeCatalogFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.design) {
|
||||
await updateVolumeCatalog(form.value).finally(() => (buttonLoading.value = false));
|
||||
} else {
|
||||
await addVolumeCatalog(form.value).finally(() => (buttonLoading.value = false));
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleDownload = (row: any) => {
|
||||
proxy?.$download.oss(row.fileId);
|
||||
};
|
||||
|
||||
/** 上传文件提交 */
|
||||
const onSubmit = async () => {
|
||||
buttonLoading.value = true;
|
||||
let cancellationIds = [];
|
||||
let fileIds = [];
|
||||
if (uploadForm.cancellationIds && uploadForm.cancellationIds.length > 0) {
|
||||
cancellationIds = uploadForm.cancellationIds.split(',');
|
||||
}
|
||||
if (uploadForm.fileIds && uploadForm.fileIds.length > 0) {
|
||||
fileIds = uploadForm.fileIds.split(',');
|
||||
}
|
||||
let obj = {
|
||||
volumeCatalogId: uploadForm.volumeCatalogId,
|
||||
fileIds: fileIds,
|
||||
cancellationIds: cancellationIds,
|
||||
type: uploadForm.type
|
||||
};
|
||||
try {
|
||||
await uploadVolumeFile(obj);
|
||||
proxy?.$modal.msgSuccess('文件上传成功');
|
||||
uploadVisible.value = false;
|
||||
await getList();
|
||||
} catch (error) {
|
||||
console.error('上传文件失败:', error);
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: VolumeCatalogVO) => {
|
||||
const _ids = row?.design || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除卷册目录编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
||||
await delVolumeCatalog(_ids);
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
await getList();
|
||||
};
|
||||
|
||||
const handleUploadSuccess = async (flieList: any, res: any) => {
|
||||
proxy?.$modal.msgSuccess('文件上传成功');
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 审核按钮操作 */
|
||||
const handleAudit = async (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/drawingreview/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'update'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 查看按钮操作 */
|
||||
const handleAuditView = async (row) => {
|
||||
proxy.$tab.closePage(proxy.$route);
|
||||
proxy.$router.push({
|
||||
path: `/approval/drawingreview/indexEdit`,
|
||||
query: {
|
||||
id: row.id,
|
||||
type: 'view'
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: VolumeCatalogVO) => {
|
||||
reset();
|
||||
const _id = row?.design || ids.value[0];
|
||||
const res = await getVolumeCatalog(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改设计出图计划';
|
||||
};
|
||||
// 过程图纸
|
||||
const handleClick = () => {
|
||||
//
|
||||
};
|
||||
const handleAuditInfo = (row) => {
|
||||
// 审核图纸
|
||||
};
|
||||
onMounted(() => {
|
||||
getUserAppList();
|
||||
getList();
|
||||
});
|
||||
|
||||
//监听项目id刷新数据
|
||||
const listeningProject = watch(
|
||||
() => currentProject.value?.id,
|
||||
(nid, oid) => {
|
||||
queryParams.value.projectId = nid;
|
||||
form.value.projectId = nid;
|
||||
getUserAppList();
|
||||
getList();
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
listeningProject();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.volumeCatalog_box {
|
||||
/* .upload-demo {
|
||||
width: 100% !important;
|
||||
} */
|
||||
table {
|
||||
border-collapse: collapse; //合并为一个单一的边框
|
||||
border-color: rgba(199, 199, 199, 1); //边框颜色按实际自定义即可
|
||||
}
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
background-color: rgba(247, 247, 247, 1); //设置表格标题背景色
|
||||
height: 35px; //设置单元格最小高度
|
||||
text-align: center;
|
||||
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 {
|
||||
text-align: left;
|
||||
height: 40px; //设置单元格最小高度
|
||||
padding: 15px;
|
||||
}
|
||||
th {
|
||||
height: 35px; //设置单元格最小高度
|
||||
text-align: center;
|
||||
letter-spacing: 5px;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.table-content {
|
||||
box-shadow: 0px 0px 10px #ddd;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user