From a28cc36ac7812be5e586e5bbc886857361d660b9 Mon Sep 17 00:00:00 2001 From: guochunsi <1595020186@qq.com> Date: Wed, 4 Feb 2026 13:59:59 +0800 Subject: [PATCH 1/8] a --- src/components/ClickableTag/index.vue | 42 +++++----- src/views/admin/system/role/change-role.vue | 54 ++++++++++--- .../professionalteacherhonor/index.vue | 79 +++++++++++++++++-- .../professionaltitlerelation/index.vue | 77 +++++++++--------- 4 files changed, 175 insertions(+), 77 deletions(-) diff --git a/src/components/ClickableTag/index.vue b/src/components/ClickableTag/index.vue index 1961923..a40bce9 100644 --- a/src/components/ClickableTag/index.vue +++ b/src/components/ClickableTag/index.vue @@ -2,25 +2,21 @@ - - + + + - - - + + + @@ -36,26 +32,32 @@ - \ No newline at end of file diff --git a/src/views/professional/professionalteacherhonor/index.vue b/src/views/professional/professionalteacherhonor/index.vue index 21cfbd5..736b523 100755 --- a/src/views/professional/professionalteacherhonor/index.vue +++ b/src/views/professional/professionalteacherhonor/index.vue @@ -83,9 +83,45 @@ > - + @@ -114,8 +150,6 @@ - - @@ -199,10 +232,12 @@ import { examObj, delObj } from '/@/api/professional/professionaluser/professionalteacherhonor' -import { PROFESSIONAL_AUDIT_STATE_OPTIONS } from '/@/config/global' +import { PROFESSIONAL_AUDIT_STATE_OPTIONS, getStatusConfig } from '/@/config/global' import { defineAsyncComponent } from 'vue' const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue')) const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/index.vue')) +const ClickableTag = defineAsyncComponent(() => import('/@/components/ClickableTag/index.vue')) +const DetailPopover = defineAsyncComponent(() => import('/@/components/DetailPopover/index.vue')) const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue')) const DataForm = defineAsyncComponent(() => import('./form.vue')) const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue')) @@ -217,6 +252,13 @@ const { professional_state: professionalState } = useDict('professional_state') // 审核状态选项 const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS +// 审核状态转 ClickableTag 配置(用 options 的 icon 字符串,与 AuditState 一致为实心) +const getAuditStateTagConfig = (state: string | number) => { + const opt = getStatusConfig(auditStateOptions, state) + if (!opt) return null + return { type: opt.type, label: opt.label, leftIcon: opt.icon, effect: opt.effect || 'dark' } +} + // 无权限即无节点 const { hasAuth } = useAuth() @@ -369,4 +411,29 @@ const handleDownLoadWord = async () => { diff --git a/src/views/professional/professionaltitlerelation/index.vue b/src/views/professional/professionaltitlerelation/index.vue index dcbaf10..2ba74ec 100755 --- a/src/views/professional/professionaltitlerelation/index.vue +++ b/src/views/professional/professionaltitlerelation/index.vue @@ -1,41 +1,9 @@ @@ -234,6 +243,7 @@ const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/i const DataForm = defineAsyncComponent(() => import('./form.vue')) const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue')) const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue')) +const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue')) // 审核状态选项 const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS @@ -265,8 +275,9 @@ const search = reactive({ // 材料预览 const imgUrl = ref>([]) -// 导出加载状态 +// 导出/导入加载状态 const exportLoading = ref(false) +const importTeacherOtherInfoRef = ref() // 资格等级和工种列表 const qualificationLevelList = ref([]) @@ -414,6 +425,11 @@ const getWorkTypeName = (id: string | number) => { return item ? item.workName : '-' } +// 打开导入弹窗 +const handleImportDialog = () => { + importTeacherOtherInfoRef.value?.init('quaRelation') +} + // 加载字典数据 const loadDictData = async () => { try { diff --git a/src/views/professional/professionalteacheracademicrelation/index.vue b/src/views/professional/professionalteacheracademicrelation/index.vue index 3add3a9..54e60bc 100755 --- a/src/views/professional/professionalteacheracademicrelation/index.vue +++ b/src/views/professional/professionalteacheracademicrelation/index.vue @@ -69,6 +69,14 @@ @click="handleDownLoadWord" :loading="exportLoading">导出信息 + 导入信息 + @@ -218,6 +226,7 @@ + @@ -245,6 +254,7 @@ const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/i const DataForm = defineAsyncComponent(() => import('./form.vue')) const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue')) const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue')) +const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue')) // 审核状态选项 const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS @@ -279,6 +289,7 @@ const imgUrl = ref>([]) // 导出加载状态 const exportLoading = ref(false) +const importTeacherOtherInfoRef = ref() // 学位、学历和教育类型列表 const degreeList = ref([]) @@ -442,6 +453,11 @@ const getEducationTypeName = (id: string | number | undefined) => { return item ? item.name : '-' } +// 打开导入弹窗 +const handleImportDialog = () => { + importTeacherOtherInfoRef.value?.init('eduDegree') +} + // 加载字典数据 const loadDictData = async () => { try { diff --git a/src/views/professional/professionalteachercertificaterelation/index.vue b/src/views/professional/professionalteachercertificaterelation/index.vue index 5aff00a..5a4253a 100755 --- a/src/views/professional/professionalteachercertificaterelation/index.vue +++ b/src/views/professional/professionalteachercertificaterelation/index.vue @@ -69,6 +69,14 @@ @click="handleDownLoadWord" :loading="exportLoading">导出信息 + 导入信息 + @@ -188,6 +196,7 @@ + @@ -213,6 +222,7 @@ const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/i const DataForm = defineAsyncComponent(() => import('./form.vue')) const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue')) const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue')) +const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue')) // 审核状态选项(独立定义,防止其他页面修改时被波及) import type { StateOption } from '/@/components/AuditState/index.vue' @@ -247,6 +257,7 @@ const imgUrl = ref>([]) // 导出加载状态 const exportLoading = ref(false) +const importTeacherOtherInfoRef = ref() // 证书列表 const certificateList = ref([]) @@ -385,6 +396,11 @@ const getCertificateName = (id: string | number) => { return item ? item.cretificateName : '-' } +// 打开导入弹窗 +const handleImportDialog = () => { + importTeacherOtherInfoRef.value?.init('cerRelation') +} + // 加载字典数据 const loadDictData = async () => { try { diff --git a/src/views/professional/professionalteacherhonor/index.vue b/src/views/professional/professionalteacherhonor/index.vue index 736b523..bb265d6 100755 --- a/src/views/professional/professionalteacherhonor/index.vue +++ b/src/views/professional/professionalteacherhonor/index.vue @@ -68,6 +68,14 @@ @click="handleDownLoadWord" :loading="exportLoading">导出信息 + 导入信息 + @@ -216,6 +224,7 @@ + @@ -241,6 +250,7 @@ const DetailPopover = defineAsyncComponent(() => import('/@/components/DetailPop const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue')) const DataForm = defineAsyncComponent(() => import('./form.vue')) const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue')) +const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue')) // 消息提示 hooks const message = useMessage() @@ -281,6 +291,7 @@ const imgUrl = ref>([]) // 导出加载状态 const exportLoading = ref(false) +const importTeacherOtherInfoRef = ref() // 配置 useTable const state: BasicTableProps = reactive({ @@ -407,6 +418,11 @@ const handleDownLoadWord = async () => { } } +// 打开导入弹窗 +const handleImportDialog = () => { + importTeacherOtherInfoRef.value?.init('honor') +} + // 表格数据由 useTable(createdIsNeed 默认 true)在挂载时自动请求 diff --git a/src/views/professional/professionaltitlerelation/index.vue b/src/views/professional/professionaltitlerelation/index.vue index 2ba74ec..ba4e06d 100755 --- a/src/views/professional/professionaltitlerelation/index.vue +++ b/src/views/professional/professionaltitlerelation/index.vue @@ -104,6 +104,14 @@ @click="handleDownLoadWord" :loading="exportLoading" >导出信息 + 导入信息 +
+ +
@@ -265,6 +275,7 @@ const MultiDialog = defineAsyncComponent(() => import('/@/views/professional/tea const DataForm = defineAsyncComponent(() => import('./form.vue')) const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue')) const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue')) +const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue')) // 无权限即无节点:使用 useAuth + v-if const { hasAuth } = useAuth() @@ -462,6 +473,11 @@ const loadDictData = async () => { } } +const importTeacherOtherInfoRef=ref() +const handleImportDialog = () => { + importTeacherOtherInfoRef.value?.init('titleRelation') +} + // 初始化:仅加载下拉字典,表格数据由 useTable 在 createdIsNeed: true 时自动请求 onMounted(async () => { await loadDictData() From 7efb43a4cb6e5a203aa1bee997dc87b65ccbebcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E7=BA=A2=E5=85=B5?= <374362909@qq.com> Date: Thu, 5 Feb 2026 23:11:38 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=B1=A5=E7=BA=A6?= =?UTF-8?q?=E8=AF=84=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/purchase/purchasingAccept.ts | 67 +++ .../accept/AcceptBatchForm.vue | 199 +++++++++ .../accept/AcceptCommonForm.vue | 165 +++++++ .../accept/PurchasingAcceptModal.vue | 405 ++++++++++++++++++ .../finance/purchasingrequisition/index.vue | 23 +- 5 files changed, 857 insertions(+), 2 deletions(-) create mode 100644 src/views/finance/purchasingrequisition/accept/AcceptBatchForm.vue create mode 100644 src/views/finance/purchasingrequisition/accept/AcceptCommonForm.vue create mode 100644 src/views/finance/purchasingrequisition/accept/PurchasingAcceptModal.vue diff --git a/src/api/purchase/purchasingAccept.ts b/src/api/purchase/purchasingAccept.ts index ee54321..6ca9182 100644 --- a/src/api/purchase/purchasingAccept.ts +++ b/src/api/purchase/purchasingAccept.ts @@ -67,6 +67,73 @@ export function putObj(obj?: Object) { }) } +// ========== 履约验收流程接口 ========== + +/** + * 第一步:保存履约验收公共配置,按分期次数自动生成批次 + */ +export function saveCommonConfig(data: any) { + return request({ + url: '/purchase/purchasingAccept/saveCommonConfig', + method: 'post', + data + }) +} + +/** + * 获取履约验收公共配置及批次列表 + */ +export function getCommonConfigWithBatches(purchaseId: string) { + return request({ + url: '/purchase/purchasingAccept/commonConfigWithBatches', + method: 'get', + params: { purchaseId } + }) +} + +/** + * 第二步:更新单个批次 + */ +export function updateBatch(data: any) { + return request({ + url: '/purchase/purchasingAccept/updateBatch', + method: 'put', + data + }) +} + +/** + * 获取验收详情(含验收内容、验收小组) + */ +export function getDetail(purchaseId: string, batch?: number) { + return request({ + url: '/purchase/purchasingAccept/detail', + method: 'get', + params: { purchaseId, batch } + }) +} + +/** + * 是否允许填报方式(金额<30万) + */ +export function canFillForm(purchaseId: string) { + return request({ + url: '/purchase/purchasingAccept/canFillForm', + method: 'get', + params: { purchaseId } + }) +} + +/** + * 根据品目类型获取验收项配置 + */ +export function getAcceptanceItems(acceptanceType: string) { + return request({ + url: `/purchase/acceptanceItemConfig/listByType/${acceptanceType}`, + method: 'get' + }) +} + // ========== 工具函数 ========== /** diff --git a/src/views/finance/purchasingrequisition/accept/AcceptBatchForm.vue b/src/views/finance/purchasingrequisition/accept/AcceptBatchForm.vue new file mode 100644 index 0000000..eeb0b9f --- /dev/null +++ b/src/views/finance/purchasingrequisition/accept/AcceptBatchForm.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/src/views/finance/purchasingrequisition/accept/AcceptCommonForm.vue b/src/views/finance/purchasingrequisition/accept/AcceptCommonForm.vue new file mode 100644 index 0000000..696ac1a --- /dev/null +++ b/src/views/finance/purchasingrequisition/accept/AcceptCommonForm.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/src/views/finance/purchasingrequisition/accept/PurchasingAcceptModal.vue b/src/views/finance/purchasingrequisition/accept/PurchasingAcceptModal.vue new file mode 100644 index 0000000..af263a2 --- /dev/null +++ b/src/views/finance/purchasingrequisition/accept/PurchasingAcceptModal.vue @@ -0,0 +1,405 @@ + + + + + diff --git a/src/views/finance/purchasingrequisition/index.vue b/src/views/finance/purchasingrequisition/index.vue index d67529e..850585b 100644 --- a/src/views/finance/purchasingrequisition/index.vue +++ b/src/views/finance/purchasingrequisition/index.vue @@ -191,7 +191,7 @@ -
- + @@ -257,6 +264,9 @@ ref="formDialogRef" :dict-data="dictData" @refresh="getDataList" /> + + + @@ -268,10 +278,11 @@ import { getPage, delObj } from "/@/api/finance/purchasingrequisition"; import { useMessage, useMessageBox } from "/@/hooks/message"; import { getDicts } from '/@/api/admin/dict'; import { getTree } from '/@/api/finance/purchasingcategory'; -import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning } from '@element-plus/icons-vue' +import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning, DocumentChecked } from '@element-plus/icons-vue' // 引入组件 const FormDialog = defineAsyncComponent(() => import('./form.vue')); +const PurchasingAcceptModal = defineAsyncComponent(() => import('./accept/PurchasingAcceptModal.vue')); // 字典数据和品目树数据 const dictData = ref({ @@ -288,6 +299,7 @@ const dictData = ref({ const router = useRouter() const tableRef = ref() const formDialogRef = ref() +const acceptModalRef = ref() const searchFormRef = ref() const showSearch = ref(true) const showAddIframe = ref(false) @@ -361,6 +373,13 @@ const handleIframeMessage = (event: MessageEvent) => { } }; +/** + * 履约验收 + */ +const handleAccept = (row: any) => { + acceptModalRef.value?.open(row); +}; + /** * 删除当前行 * @param row - 当前行数据