rebuild all
This commit is contained in:
64
src/api/purchase/bidOpeningNotice.ts
Normal file
64
src/api/purchase/bidOpeningNotice.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2025, cyweb All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import request from '/@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据采购申请ID获取开标通知
|
||||||
|
* @param applyId 采购申请ID
|
||||||
|
*/
|
||||||
|
export function getNoticeByApplyId(applyId: string | number) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/bidopeningnotice/' + applyId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存开标通知(草稿)
|
||||||
|
* @param data 开标通知数据
|
||||||
|
*/
|
||||||
|
export function saveNotice(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/bidopeningnotice/save',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布开标通知
|
||||||
|
* @param data 开标通知数据
|
||||||
|
*/
|
||||||
|
export function publishNotice(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/bidopeningnotice/publish',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否可以发送开标通知
|
||||||
|
* @param applyId 采购申请ID
|
||||||
|
*/
|
||||||
|
export function canSendNotice(applyId: string | number) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/bidopeningnotice/can-send/' + applyId,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -272,3 +272,38 @@ export function finalizeDoc(data: any) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取采购代表设置信息
|
||||||
|
* @param applyId 采购申请ID
|
||||||
|
*/
|
||||||
|
export function getReviewerSetting(applyId: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/purchase/purchasingdoc/reviewer/${applyId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置采购代表
|
||||||
|
* @param data 设置信息
|
||||||
|
*/
|
||||||
|
export function setReviewerSetting(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingdoc/reviewer/set',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机抽取采购代表
|
||||||
|
* @param data 候选人列表
|
||||||
|
*/
|
||||||
|
export function randomSelectReviewer(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingdoc/reviewer/random',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ export function getPage(params?: any) {
|
|||||||
* 通过id查询
|
* 通过id查询
|
||||||
* @param id ID
|
* @param id ID
|
||||||
*/
|
*/
|
||||||
export function getObj(id: number) {
|
export function getObj(id: string | number) {
|
||||||
return request({
|
return request({
|
||||||
url: '/purchase/purchasingapply/' + id,
|
url: '/purchase/purchasingapply/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
@@ -123,7 +123,7 @@ export function saveImplementType(id: number | string, implementType: string) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/purchase/purchasingapply/save-implement-type',
|
url: '/purchase/purchasingapply/save-implement-type',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: { id: Number(id), implementType }
|
data: { id: id, implementType }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { staticRoutes, notFoundAndNoPower } from '/@/router/route';
|
|||||||
import { initBackEndControlRoutes } from '/@/router/backEnd';
|
import { initBackEndControlRoutes } from '/@/router/backEnd';
|
||||||
import { flowConfig } from "/@/flow/designer/config/flow-config";
|
import { flowConfig } from "/@/flow/designer/config/flow-config";
|
||||||
import { replaceRouterRoute } from "/@/flow/support/extend";
|
import { replaceRouterRoute } from "/@/flow/support/extend";
|
||||||
|
import { NextLoading } from '/@/utils/loading';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
|
* 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
|
||||||
@@ -148,6 +149,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
// 路由加载后
|
// 路由加载后
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
|
NextLoading.done();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 导出路由
|
// 导出路由
|
||||||
|
|||||||
@@ -99,6 +99,14 @@ export const staticRoutes: Array<RouteRecordRaw> = [
|
|||||||
isAuth: true,
|
isAuth: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/purchase/purchasingrequisition/add',
|
||||||
|
name: 'purchase.purchasingrequisition.add',
|
||||||
|
component: () => import('/@/views/purchase/purchasingrequisition/add.vue'),
|
||||||
|
meta: {
|
||||||
|
isAuth: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
...staticRoutesFlow
|
...staticRoutesFlow
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
{{ t('sysmenu.permission') }}
|
{{ t('sysmenu.permission') }}
|
||||||
<tip content="对应后台接口@PreAuthorize注解入参字符串"></tip>
|
<tip content="对应后台接口@PreAuthorize注解入参字符串"></tip>
|
||||||
</template>
|
</template>
|
||||||
<el-input v-model="state.ruleForm.permission" maxlength="30" :placeholder="$t('sysmenu.inputPermissionTip')"/>
|
<el-input v-model="state.ruleForm.permission" maxlength="100" :placeholder="$t('sysmenu.inputPermissionTip')"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('sysmenu.sortOrder')" prop="sortOrder">
|
<el-form-item :label="$t('sysmenu.sortOrder')" prop="sortOrder">
|
||||||
<el-input-number v-model="state.ruleForm.sortOrder" :min="0" controls-position="right"/>
|
<el-input-number v-model="state.ruleForm.sortOrder" :min="0" controls-position="right"/>
|
||||||
|
|||||||
@@ -72,6 +72,17 @@
|
|||||||
<org-selector v-model:orgList="assetAdminList" type="user" :multiple="false" @update:orgList="onAssetAdminChange" />
|
<org-selector v-model:orgList="assetAdminList" type="user" :multiple="false" @update:orgList="onAssetAdminChange" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="8" class="mb20" v-if="form.hasContract === '0'">
|
||||||
|
<el-form-item label="成交金额" prop="transactionAmount">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.transactionAmount"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
placeholder="请输入成交金额"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
@@ -113,6 +124,7 @@ const form = reactive({
|
|||||||
purchaserName: '',
|
purchaserName: '',
|
||||||
assetAdminId: '',
|
assetAdminId: '',
|
||||||
assetAdminName: '',
|
assetAdminName: '',
|
||||||
|
transactionAmount: null,
|
||||||
...props.modelValue,
|
...props.modelValue,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,7 @@ const loadData = async () => {
|
|||||||
totalPhases: config.common.totalPhases || 1,
|
totalPhases: config.common.totalPhases || 1,
|
||||||
supplierName: config.common.supplierName || '',
|
supplierName: config.common.supplierName || '',
|
||||||
supplierContact: config.common.supplierContact || '',
|
supplierContact: config.common.supplierContact || '',
|
||||||
|
transactionAmount: config.common.transactionAmount || null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,6 +276,7 @@ const saveCommonConfig = async () => {
|
|||||||
purchaserName: String(form.purchaserName ?? ''),
|
purchaserName: String(form.purchaserName ?? ''),
|
||||||
assetAdminId: String(form.assetAdminId ?? ''),
|
assetAdminId: String(form.assetAdminId ?? ''),
|
||||||
assetAdminName: String(form.assetAdminName ?? ''),
|
assetAdminName: String(form.assetAdminName ?? ''),
|
||||||
|
transactionAmount: form.transactionAmount ?? null,
|
||||||
})
|
})
|
||||||
useMessage().success('保存成功')
|
useMessage().success('保存成功')
|
||||||
await loadData()
|
await loadData()
|
||||||
@@ -353,6 +355,7 @@ const DEFAULT_COMMON_FORM = {
|
|||||||
purchaserName: '',
|
purchaserName: '',
|
||||||
assetAdminId: '',
|
assetAdminId: '',
|
||||||
assetAdminName: '',
|
assetAdminName: '',
|
||||||
|
transactionAmount: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 将弹窗内所有内容恢复为初始空值(替换整个对象以确保引用变化) */
|
/** 将弹窗内所有内容恢复为初始空值(替换整个对象以确保引用变化) */
|
||||||
|
|||||||
@@ -1204,7 +1204,7 @@ const handleCancel = () => {
|
|||||||
async function loadDetail(applyId: string | number) {
|
async function loadDetail(applyId: string | number) {
|
||||||
if (!applyId) return;
|
if (!applyId) return;
|
||||||
try {
|
try {
|
||||||
const res = await getObj(Number(applyId));
|
const res = await getObj(String(applyId));
|
||||||
const detail = res?.data;
|
const detail = res?.data;
|
||||||
if (detail && typeof detail === 'object') {
|
if (detail && typeof detail === 'object') {
|
||||||
Object.assign(dataForm, {
|
Object.assign(dataForm, {
|
||||||
|
|||||||
@@ -127,6 +127,119 @@
|
|||||||
<el-tab-pane label="审核记录" name="audit">
|
<el-tab-pane label="审核记录" name="audit">
|
||||||
<AuditRecordList :apply-id="applyId" ref="auditRecordListRef" />
|
<AuditRecordList :apply-id="applyId" ref="auditRecordListRef" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<!-- 采购代表设置(仅需求部门审核时显示) -->
|
||||||
|
<el-tab-pane v-if="canSetReviewer" label="采购代表设置" name="reviewer">
|
||||||
|
<ReviewerSetting :apply-id="applyId" @saved="handleReviewerSaved" />
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
|
<!-- 开标通知 - 仅招标代理模式且状态为已完成时显示 -->
|
||||||
|
<el-tab-pane v-if="showBidOpeningNotice" label="开标通知" name="bidOpening">
|
||||||
|
<div class="bid-opening-form" v-loading="bidOpeningLoading">
|
||||||
|
<el-form :model="bidOpeningForm" :rules="bidOpeningRules" ref="bidOpeningFormRef" label-width="120px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="项目名称">
|
||||||
|
<el-input v-model="rowData.projectName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="开标时间" prop="openTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="bidOpeningForm.openTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="请选择开标时间"
|
||||||
|
style="width: 100%"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="开标地点" prop="openLocation">
|
||||||
|
<el-input v-model="bidOpeningForm.openLocation" placeholder="请输入开标地点" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="公示网址">
|
||||||
|
<el-input v-model="bidOpeningForm.publicUrl" placeholder="请输入公示网址" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="代理联系人" prop="agentContactName">
|
||||||
|
<el-input v-model="bidOpeningForm.agentContactName" placeholder="请输入代理联系人姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话" prop="agentContactPhone">
|
||||||
|
<el-input v-model="bidOpeningForm.agentContactPhone" placeholder="请输入代理联系人电话" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="招标确认函">
|
||||||
|
<el-upload
|
||||||
|
:action="uploadAction"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:data="{ fileType: '131', purchaseId: applyId }"
|
||||||
|
:on-success="(res: any, file: any) => handleBidFileSuccess(res, file, 'bidConfirmationLetter')"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:show-file-list="false"
|
||||||
|
accept=".doc,.docx,.pdf,.jpg,.jpeg,.png">
|
||||||
|
<el-button type="primary" icon="Upload">上传文件</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<div v-if="bidOpeningForm.bidConfirmationLetter" class="file-info">
|
||||||
|
<el-icon><Document /></el-icon>
|
||||||
|
<span>已上传</span>
|
||||||
|
<el-button type="primary" link @click="viewFile(bidOpeningForm.bidConfirmationLetter)">查看</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="授权书">
|
||||||
|
<el-upload
|
||||||
|
:action="uploadAction"
|
||||||
|
:headers="uploadHeaders"
|
||||||
|
:data="{ fileType: '132', purchaseId: applyId }"
|
||||||
|
:on-success="(res: any, file: any) => handleBidFileSuccess(res, file, 'authorizationLetter')"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:show-file-list="false"
|
||||||
|
accept=".doc,.docx,.pdf,.jpg,.jpeg,.png">
|
||||||
|
<el-button type="primary" icon="Upload">上传文件</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<div v-if="bidOpeningForm.authorizationLetter" class="file-info">
|
||||||
|
<el-icon><Document /></el-icon>
|
||||||
|
<span>已上传</span>
|
||||||
|
<el-button type="primary" link @click="viewFile(bidOpeningForm.authorizationLetter)">查看</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="备注">
|
||||||
|
<el-input v-model="bidOpeningForm.remarks" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24" class="form-actions">
|
||||||
|
<el-button type="info" :loading="bidOpeningSaving" @click="handleSaveBidOpeningDraft">保存草稿</el-button>
|
||||||
|
<el-button type="success" :loading="bidOpeningPublishing" @click="handlePublishBidOpening">发布通知</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<!-- 已发布提示 -->
|
||||||
|
<el-alert v-if="bidOpeningNoticeStatus === 'PUBLISHED'" type="success" :closable="false" class="mt-4">
|
||||||
|
<template #title>
|
||||||
|
<span>开标通知已于 {{ bidOpeningForm.publishTime }} 发布</span>
|
||||||
|
</template>
|
||||||
|
</el-alert>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
<!-- 操作区域 -->
|
<!-- 操作区域 -->
|
||||||
@@ -244,9 +357,17 @@ import {
|
|||||||
submitToAsset as submitToAssetApi,
|
submitToAsset as submitToAssetApi,
|
||||||
finalizeDoc as finalizeDocApi
|
finalizeDoc as finalizeDocApi
|
||||||
} from '/@/api/purchase/docProcess'
|
} from '/@/api/purchase/docProcess'
|
||||||
|
import {
|
||||||
|
getNoticeByApplyId,
|
||||||
|
saveNotice,
|
||||||
|
publishNotice,
|
||||||
|
canSendNotice
|
||||||
|
} from '/@/api/purchase/bidOpeningNotice'
|
||||||
import type { UploadInstance, UploadProps, UploadUserFile } from 'element-plus'
|
import type { UploadInstance, UploadProps, UploadUserFile } from 'element-plus'
|
||||||
|
import { Document } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const AuditRecordList = defineAsyncComponent(() => import('./AuditRecordList.vue'))
|
const AuditRecordList = defineAsyncComponent(() => import('./AuditRecordList.vue'))
|
||||||
|
const ReviewerSetting = defineAsyncComponent(() => import('./ReviewerSetting.vue'))
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
mode: 'agent' | 'audit'
|
mode: 'agent' | 'audit'
|
||||||
@@ -297,6 +418,33 @@ const supplyUploadForm = ref({
|
|||||||
fileRemark: ''
|
fileRemark: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 开标通知相关
|
||||||
|
const bidOpeningFormRef = ref()
|
||||||
|
const bidOpeningLoading = ref(false)
|
||||||
|
const bidOpeningSaving = ref(false)
|
||||||
|
const bidOpeningPublishing = ref(false)
|
||||||
|
const bidOpeningNoticeStatus = ref('')
|
||||||
|
const bidOpeningForm = ref({
|
||||||
|
id: '',
|
||||||
|
applyId: '',
|
||||||
|
projectName: '',
|
||||||
|
openTime: '',
|
||||||
|
openLocation: '',
|
||||||
|
agentContactName: '',
|
||||||
|
agentContactPhone: '',
|
||||||
|
publicUrl: '',
|
||||||
|
bidConfirmationLetter: '',
|
||||||
|
authorizationLetter: '',
|
||||||
|
remarks: '',
|
||||||
|
publishTime: ''
|
||||||
|
})
|
||||||
|
const bidOpeningRules = {
|
||||||
|
openTime: [{ required: true, message: '请选择开标时间', trigger: 'change' }],
|
||||||
|
openLocation: [{ required: true, message: '请输入开标地点', trigger: 'blur' }],
|
||||||
|
agentContactName: [{ required: true, message: '请输入代理联系人姓名', trigger: 'blur' }],
|
||||||
|
agentContactPhone: [{ required: true, message: '请输入代理联系人电话', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
// 弹窗标题
|
// 弹窗标题
|
||||||
const dialogTitle = computed(() => {
|
const dialogTitle = computed(() => {
|
||||||
return props.mode === 'agent' ? `处理项目 - ${rowData.value.purchaseNo || ''}` : '招标文件审核'
|
return props.mode === 'agent' ? `处理项目 - ${rowData.value.purchaseNo || ''}` : '招标文件审核'
|
||||||
@@ -336,6 +484,12 @@ const isReviewing = computed(() => ['ASSET_REVIEWING', 'DEPT_REVIEWING', 'AUDIT_
|
|||||||
const isConfirming = computed(() => statusField.value === 'ASSET_CONFIRMING')
|
const isConfirming = computed(() => statusField.value === 'ASSET_CONFIRMING')
|
||||||
const isCompleted = computed(() => statusField.value === 'COMPLETED')
|
const isCompleted = computed(() => statusField.value === 'COMPLETED')
|
||||||
|
|
||||||
|
// 是否显示开标通知Tab(招标代理模式且状态为已完成)
|
||||||
|
const showBidOpeningNotice = computed(() => props.mode === 'agent' && isCompleted.value)
|
||||||
|
|
||||||
|
// 是否显示采购代表设置Tab(需求部门审核中且有提交权限)
|
||||||
|
const canSetReviewer = computed(() => statusField.value === 'DEPT_REVIEWING' && availableActions.value.includes('submitToAsset'))
|
||||||
|
|
||||||
// 上传配置
|
// 上传配置
|
||||||
const uploadAction = computed(() => {
|
const uploadAction = computed(() => {
|
||||||
const baseUrl = import.meta.env.VITE_API_URL || ''
|
const baseUrl = import.meta.env.VITE_API_URL || ''
|
||||||
@@ -365,6 +519,9 @@ const open = async (row: any) => {
|
|||||||
fileList.value = []
|
fileList.value = []
|
||||||
uploadedFileData.value = null
|
uploadedFileData.value = null
|
||||||
|
|
||||||
|
// 重置开标通知表单
|
||||||
|
resetBidOpeningForm()
|
||||||
|
|
||||||
// 获取申请ID(兼容 id 和 applyId 两种字段名)
|
// 获取申请ID(兼容 id 和 applyId 两种字段名)
|
||||||
applyId.value = row.applyId || row.id
|
applyId.value = row.applyId || row.id
|
||||||
|
|
||||||
@@ -380,6 +537,10 @@ const open = async (row: any) => {
|
|||||||
loadRequirementFiles()
|
loadRequirementFiles()
|
||||||
// 加载招标文件
|
// 加载招标文件
|
||||||
loadDocList()
|
loadDocList()
|
||||||
|
// 加载开标通知(如果是招标代理模式且状态为已完成)
|
||||||
|
if (props.mode === 'agent') {
|
||||||
|
loadBidOpeningNotice()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadRequirementFiles = async () => {
|
const loadRequirementFiles = async () => {
|
||||||
@@ -801,6 +962,154 @@ const submitFinalize = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 开标通知相关方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置开标通知表单
|
||||||
|
*/
|
||||||
|
const resetBidOpeningForm = () => {
|
||||||
|
bidOpeningForm.value = {
|
||||||
|
id: '',
|
||||||
|
applyId: '',
|
||||||
|
projectName: '',
|
||||||
|
openTime: '',
|
||||||
|
openLocation: '',
|
||||||
|
agentContactName: '',
|
||||||
|
agentContactPhone: '',
|
||||||
|
publicUrl: '',
|
||||||
|
bidConfirmationLetter: '',
|
||||||
|
authorizationLetter: '',
|
||||||
|
remarks: '',
|
||||||
|
publishTime: ''
|
||||||
|
}
|
||||||
|
bidOpeningNoticeStatus.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载开标通知
|
||||||
|
*/
|
||||||
|
const loadBidOpeningNotice = async () => {
|
||||||
|
if (!applyId.value) return
|
||||||
|
bidOpeningLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getNoticeByApplyId(applyId.value)
|
||||||
|
if (res?.code === 0 || res?.code === 200) {
|
||||||
|
const data = res.data
|
||||||
|
if (data) {
|
||||||
|
bidOpeningForm.value = {
|
||||||
|
id: data.id || '',
|
||||||
|
applyId: data.applyId || applyId.value,
|
||||||
|
projectName: data.projectName || rowData.value.projectName || '',
|
||||||
|
openTime: data.openTime || '',
|
||||||
|
openLocation: data.openLocation || '',
|
||||||
|
agentContactName: data.agentContactName || '',
|
||||||
|
agentContactPhone: data.agentContactPhone || '',
|
||||||
|
publicUrl: data.publicUrl || '',
|
||||||
|
bidConfirmationLetter: data.bidConfirmationLetter || '',
|
||||||
|
authorizationLetter: data.authorizationLetter || '',
|
||||||
|
remarks: data.remarks || '',
|
||||||
|
publishTime: data.publishTime || ''
|
||||||
|
}
|
||||||
|
bidOpeningNoticeStatus.value = data.status || ''
|
||||||
|
} else {
|
||||||
|
bidOpeningForm.value.applyId = applyId.value
|
||||||
|
bidOpeningForm.value.projectName = rowData.value.projectName || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略错误,可能是第一次创建
|
||||||
|
} finally {
|
||||||
|
bidOpeningLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开标通知文件上传成功回调
|
||||||
|
*/
|
||||||
|
const handleBidFileSuccess = (response: any, file: any, field: string) => {
|
||||||
|
if (response?.code === 0 || response?.code === 200) {
|
||||||
|
bidOpeningForm.value[field] = response.data.remark || response.data.filePath
|
||||||
|
useMessage().success('文件上传成功')
|
||||||
|
} else {
|
||||||
|
useMessage().error(response?.msg || '文件上传失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看文件
|
||||||
|
*/
|
||||||
|
const viewFile = (url: string) => {
|
||||||
|
if (url) {
|
||||||
|
window.open(url, '_blank')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存开标通知草稿
|
||||||
|
*/
|
||||||
|
const handleSaveBidOpeningDraft = async () => {
|
||||||
|
try {
|
||||||
|
await bidOpeningFormRef.value?.validate()
|
||||||
|
} catch {
|
||||||
|
useMessage().warning('请填写必填项')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bidOpeningSaving.value = true
|
||||||
|
try {
|
||||||
|
const res = await saveNotice({
|
||||||
|
...bidOpeningForm.value,
|
||||||
|
applyId: applyId.value
|
||||||
|
})
|
||||||
|
if (res?.code === 0 || res?.code === 200) {
|
||||||
|
useMessage().success('保存成功')
|
||||||
|
await loadBidOpeningNotice()
|
||||||
|
} else {
|
||||||
|
useMessage().error(res?.msg || '保存失败')
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
useMessage().error(e?.msg || '保存失败')
|
||||||
|
} finally {
|
||||||
|
bidOpeningSaving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布开标通知
|
||||||
|
*/
|
||||||
|
const handlePublishBidOpening = async () => {
|
||||||
|
try {
|
||||||
|
await bidOpeningFormRef.value?.validate()
|
||||||
|
} catch {
|
||||||
|
useMessage().warning('请填写必填项')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await useMessageBox().confirm('确定要发布开标通知吗?发布后将无法修改。')
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bidOpeningPublishing.value = true
|
||||||
|
try {
|
||||||
|
const res = await publishNotice({
|
||||||
|
...bidOpeningForm.value,
|
||||||
|
applyId: applyId.value
|
||||||
|
})
|
||||||
|
if (res?.code === 0 || res?.code === 200) {
|
||||||
|
useMessage().success('发布成功')
|
||||||
|
await loadBidOpeningNotice()
|
||||||
|
} else {
|
||||||
|
useMessage().error(res?.msg || '发布失败')
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
useMessage().error(e?.msg || '发布失败')
|
||||||
|
} finally {
|
||||||
|
bidOpeningPublishing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
visible.value = false
|
visible.value = false
|
||||||
}
|
}
|
||||||
@@ -841,6 +1150,11 @@ const getFileTypeLabel = (type: string) => {
|
|||||||
return labelMap[type] || type
|
return labelMap[type] || type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 采购代表设置保存成功回调
|
||||||
|
const handleReviewerSaved = () => {
|
||||||
|
emit('refresh')
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -868,4 +1182,29 @@ defineExpose({ open })
|
|||||||
.mt-4 {
|
.mt-4 {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bid-opening-form {
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
.file-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #606266;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
<template>
|
||||||
|
<div class="reviewer-setting">
|
||||||
|
<el-form :model="formData" label-width="100px" v-loading="loading">
|
||||||
|
<!-- 当前采购代表 -->
|
||||||
|
<el-form-item label="当前代表" v-if="currentRepresentor.teacherName">
|
||||||
|
<el-tag type="success">{{ currentRepresentor.teacherName }} ({{ currentRepresentor.teacherNo }})</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 选择方式 -->
|
||||||
|
<el-form-item label="选择方式">
|
||||||
|
<el-radio-group v-model="formData.selectMode" @change="handleSelectModeChange">
|
||||||
|
<el-radio label="DESIGNATED">指定人员</el-radio>
|
||||||
|
<el-radio label="RANDOM">随机抽取</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 指定人员模式 -->
|
||||||
|
<el-form-item v-if="formData.selectMode === 'DESIGNATED'" label="选择人员" required>
|
||||||
|
<org-selector
|
||||||
|
v-model:orgList="selectedUserList"
|
||||||
|
type="user"
|
||||||
|
:multiple="false"
|
||||||
|
@update:orgList="handleUserChange" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 随机抽取模式 -->
|
||||||
|
<template v-if="formData.selectMode === 'RANDOM'">
|
||||||
|
<el-form-item label="选择候选人" required>
|
||||||
|
<org-selector
|
||||||
|
v-model:orgList="candidateUserList"
|
||||||
|
type="user"
|
||||||
|
:multiple="true"
|
||||||
|
@update:orgList="handleCandidateChange" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 候选人列表 -->
|
||||||
|
<el-form-item label="候选人列表" v-if="candidates.length > 0">
|
||||||
|
<el-table :data="candidates" stripe size="small" max-height="200">
|
||||||
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column prop="teacherNo" label="工号" width="120" />
|
||||||
|
<el-table-column prop="teacherName" label="姓名" />
|
||||||
|
</el-table>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 随机抽取结果 -->
|
||||||
|
<el-form-item label="抽取结果">
|
||||||
|
<div class="random-roller">
|
||||||
|
<span v-if="rollingName" class="rolling">{{ rollingName }}</span>
|
||||||
|
<span v-else-if="selectedCandidate.teacherName" class="selected">
|
||||||
|
已抽取:{{ selectedCandidate.teacherName }} ({{ selectedCandidate.teacherNo }})
|
||||||
|
</span>
|
||||||
|
<span v-else class="placeholder">点击下方按钮进行随机抽取</span>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 随机抽取按钮 -->
|
||||||
|
<el-form-item v-if="candidates.length > 1">
|
||||||
|
<el-button type="primary" :loading="rolling" @click="handleRandomSelect">
|
||||||
|
{{ rolling ? '抽取中...' : '随机抽取' }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 保存按钮 -->
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="saving" :disabled="!canSave" @click="handleSave">
|
||||||
|
保存设置
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ReviewerSetting">
|
||||||
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { useMessage } from '/@/hooks/message'
|
||||||
|
import { getReviewerSetting, setReviewerSetting, randomSelectReviewer } from '/@/api/purchase/docProcess'
|
||||||
|
import orgSelector from '/@/components/OrgSelector/index.vue'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
applyId: string | number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'saved'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 常量
|
||||||
|
const SELECT_MODE = {
|
||||||
|
DESIGNATED: 'DESIGNATED',
|
||||||
|
RANDOM: 'RANDOM',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = ref({
|
||||||
|
selectMode: 'DESIGNATED' as 'DESIGNATED' | 'RANDOM',
|
||||||
|
teacherNo: '',
|
||||||
|
teacherName: '',
|
||||||
|
candidates: [] as Array<{ teacherNo: string; teacherName: string }>
|
||||||
|
})
|
||||||
|
|
||||||
|
// 当前采购代表(已有设置)
|
||||||
|
const currentRepresentor = ref({
|
||||||
|
teacherNo: '',
|
||||||
|
teacherName: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 用户选择相关
|
||||||
|
const selectedUserList = ref<any[]>([])
|
||||||
|
const candidateUserList = ref<any[]>([])
|
||||||
|
|
||||||
|
// 候选人列表
|
||||||
|
const candidates = ref<Array<{ teacherNo: string; teacherName: string }>>([])
|
||||||
|
|
||||||
|
// 随机抽取相关
|
||||||
|
const rolling = ref(false)
|
||||||
|
const rollingName = ref('')
|
||||||
|
const selectedCandidate = ref<{ teacherNo: string; teacherName: string }>({ teacherNo: '', teacherName: '' })
|
||||||
|
let rollInterval: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(false)
|
||||||
|
const saving = ref(false)
|
||||||
|
|
||||||
|
// 是否可以保存
|
||||||
|
const canSave = computed(() => {
|
||||||
|
if (formData.value.selectMode === SELECT_MODE.DESIGNATED) {
|
||||||
|
return formData.value.teacherNo && formData.value.teacherName
|
||||||
|
} else {
|
||||||
|
return formData.value.teacherNo && formData.value.teacherName && candidates.value.length > 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理选择方式变化
|
||||||
|
const handleSelectModeChange = () => {
|
||||||
|
formData.value.teacherNo = ''
|
||||||
|
formData.value.teacherName = ''
|
||||||
|
formData.value.candidates = []
|
||||||
|
selectedUserList.value = []
|
||||||
|
candidateUserList.value = []
|
||||||
|
candidates.value = []
|
||||||
|
selectedCandidate.value = { teacherNo: '', teacherName: '' }
|
||||||
|
rollingName.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理指定人员变化
|
||||||
|
const handleUserChange = (list: any[]) => {
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
const user = list[0]
|
||||||
|
formData.value.teacherNo = user.username || user.userName || ''
|
||||||
|
formData.value.teacherName = user.name || user.realName || ''
|
||||||
|
} else {
|
||||||
|
formData.value.teacherNo = ''
|
||||||
|
formData.value.teacherName = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理候选人变化
|
||||||
|
const handleCandidateChange = (list: any[]) => {
|
||||||
|
candidates.value = (list || []).map(user => ({
|
||||||
|
teacherNo: user.username || user.userName || '',
|
||||||
|
teacherName: user.name || user.realName || ''
|
||||||
|
}))
|
||||||
|
// 重置已选结果
|
||||||
|
if (candidates.value.length > 0) {
|
||||||
|
selectedCandidate.value = { ...candidates.value[0] }
|
||||||
|
formData.value.teacherNo = selectedCandidate.value.teacherNo
|
||||||
|
formData.value.teacherName = selectedCandidate.value.teacherName
|
||||||
|
} else {
|
||||||
|
selectedCandidate.value = { teacherNo: '', teacherName: '' }
|
||||||
|
formData.value.teacherNo = ''
|
||||||
|
formData.value.teacherName = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 随机抽取动画
|
||||||
|
const startRollingAnimation = (finalCandidate: { teacherNo: string; teacherName: string }) => {
|
||||||
|
if (candidates.value.length === 0) return
|
||||||
|
|
||||||
|
if (rollInterval) {
|
||||||
|
clearInterval(rollInterval)
|
||||||
|
rollInterval = null
|
||||||
|
}
|
||||||
|
|
||||||
|
rollingName.value = ''
|
||||||
|
rolling.value = true
|
||||||
|
|
||||||
|
let currentIndex = 0
|
||||||
|
const totalDuration = 2000
|
||||||
|
const intervalTime = 80
|
||||||
|
|
||||||
|
rollInterval = setInterval(() => {
|
||||||
|
rollingName.value = candidates.value[currentIndex].teacherName
|
||||||
|
currentIndex = (currentIndex + 1) % candidates.value.length
|
||||||
|
}, intervalTime)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (rollInterval) {
|
||||||
|
clearInterval(rollInterval)
|
||||||
|
rollInterval = null
|
||||||
|
}
|
||||||
|
rolling.value = false
|
||||||
|
rollingName.value = ''
|
||||||
|
selectedCandidate.value = finalCandidate
|
||||||
|
formData.value.teacherNo = finalCandidate.teacherNo
|
||||||
|
formData.value.teacherName = finalCandidate.teacherName
|
||||||
|
}, totalDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行随机抽取
|
||||||
|
const handleRandomSelect = async () => {
|
||||||
|
if (candidates.value.length < 2) {
|
||||||
|
useMessage().warning('请至少选择2位候选人')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rolling.value = true
|
||||||
|
try {
|
||||||
|
const res = await randomSelectReviewer({
|
||||||
|
applyId: props.applyId,
|
||||||
|
selectMode: SELECT_MODE.RANDOM,
|
||||||
|
candidates: candidates.value
|
||||||
|
})
|
||||||
|
const result = res?.data || res
|
||||||
|
if (result?.teacherNo) {
|
||||||
|
startRollingAnimation({
|
||||||
|
teacherNo: result.teacherNo,
|
||||||
|
teacherName: result.teacherName || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
rolling.value = false
|
||||||
|
useMessage().error(e?.msg || '随机抽取失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存设置
|
||||||
|
const handleSave = async () => {
|
||||||
|
if (!canSave.value) {
|
||||||
|
useMessage().warning('请完善设置信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
saving.value = true
|
||||||
|
try {
|
||||||
|
const params: any = {
|
||||||
|
applyId: props.applyId,
|
||||||
|
selectMode: formData.value.selectMode,
|
||||||
|
teacherNo: formData.value.teacherNo,
|
||||||
|
teacherName: formData.value.teacherName
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formData.value.selectMode === SELECT_MODE.RANDOM) {
|
||||||
|
params.candidates = candidates.value
|
||||||
|
}
|
||||||
|
|
||||||
|
await setReviewerSetting(params)
|
||||||
|
useMessage().success('保存成功')
|
||||||
|
emit('saved')
|
||||||
|
await loadData()
|
||||||
|
} catch (e: any) {
|
||||||
|
useMessage().error(e?.msg || '保存失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载数据
|
||||||
|
const loadData = async () => {
|
||||||
|
if (!props.applyId) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getReviewerSetting(props.applyId)
|
||||||
|
const data = res?.data || res
|
||||||
|
if (data) {
|
||||||
|
currentRepresentor.value = {
|
||||||
|
teacherNo: data.teacherNo || '',
|
||||||
|
teacherName: data.teacherName || ''
|
||||||
|
}
|
||||||
|
formData.value.selectMode = data.selectMode || SELECT_MODE.DESIGNATED
|
||||||
|
formData.value.teacherNo = data.teacherNo || ''
|
||||||
|
formData.value.teacherName = data.teacherName || ''
|
||||||
|
|
||||||
|
if (data.candidateList && data.candidateList.length > 0) {
|
||||||
|
candidates.value = data.candidateList
|
||||||
|
formData.value.candidates = data.candidateList
|
||||||
|
// 回显候选人
|
||||||
|
candidateUserList.value = data.candidateList.map((c: any) => ({
|
||||||
|
username: c.teacherNo,
|
||||||
|
userName: c.teacherNo,
|
||||||
|
name: c.teacherName,
|
||||||
|
realName: c.teacherName
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.teacherNo && data.selectMode === SELECT_MODE.DESIGNATED) {
|
||||||
|
selectedUserList.value = [{
|
||||||
|
username: data.teacherNo,
|
||||||
|
userName: data.teacherNo,
|
||||||
|
name: data.teacherName,
|
||||||
|
realName: data.teacherName
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.selectMode === SELECT_MODE.RANDOM && data.teacherNo) {
|
||||||
|
selectedCandidate.value = {
|
||||||
|
teacherNo: data.teacherNo,
|
||||||
|
teacherName: data.teacherName || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// 忽略错误
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadData()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (rollInterval) {
|
||||||
|
clearInterval(rollInterval)
|
||||||
|
rollInterval = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.reviewer-setting {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.random-roller {
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
border-radius: 4px;
|
||||||
|
min-height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.rolling {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
animation: blink 0.1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--el-color-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: var(--el-text-color-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.7; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -316,6 +316,7 @@ const handleRevokeAgent = async () => {
|
|||||||
const handleSaveImplementType = async () => {
|
const handleSaveImplementType = async () => {
|
||||||
|
|
||||||
const id = applyRow.value?.id ?? applyId.value
|
const id = applyRow.value?.id ?? applyId.value
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
useMessage().warning('无法获取申请单ID')
|
useMessage().warning('无法获取申请单ID')
|
||||||
return
|
return
|
||||||
@@ -326,6 +327,7 @@ const handleSaveImplementType = async () => {
|
|||||||
}
|
}
|
||||||
saveTypeSubmitting.value = true
|
saveTypeSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await saveImplementType(id, implementType.value)
|
await saveImplementType(id, implementType.value)
|
||||||
useMessage().success('保存成功')
|
useMessage().success('保存成功')
|
||||||
step1Completed.value = true
|
step1Completed.value = true
|
||||||
|
|||||||
Reference in New Issue
Block a user