no message

pull/781/head
zy 2025-05-11 18:24:59 +08:00
parent 50691d39d1
commit f6c7154f1f
18 changed files with 784 additions and 102 deletions

23
package-lock.json generated
View File

@ -57,6 +57,7 @@
"vue-dompurify-html": "^4.1.4", "vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.10.2", "vue-i18n": "9.10.2",
"vue-router": "4.4.5", "vue-router": "4.4.5",
"vue-signature-pad": "^3.0.2",
"vue-types": "^5.1.1", "vue-types": "^5.1.1",
"vue3-signature": "^0.2.4", "vue3-signature": "^0.2.4",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
@ -12844,6 +12845,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/merge-images": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/merge-images/-/merge-images-1.2.0.tgz",
"integrity": "sha512-hEGvgnTdXr08uzGvEArxRsKpy7WmozM73YaSi4s5IYF4LxrhANpqfHaz9CgBZ5+0+s2NsjPnPdStz3aCc0Yulw==",
"license": "MIT"
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -16967,6 +16974,22 @@
"vue": "^3.2.0" "vue": "^3.2.0"
} }
}, },
"node_modules/vue-signature-pad": {
"version": "3.0.2",
"resolved": "https://registry.npmmirror.com/vue-signature-pad/-/vue-signature-pad-3.0.2.tgz",
"integrity": "sha512-o25o+lROfCmzASS2+fU8ZV801kV+D4/02zkZ+ez3NKeiUmbxW7kwlUf5oKQkvA+l7Ou9xGsGLsirBLch3jyX8A==",
"license": "MIT",
"dependencies": {
"merge-images": "^1.1.0",
"signature_pad": "^3.0.0-beta.3"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/vue-template-compiler": { "node_modules/vue-template-compiler": {
"version": "2.7.16", "version": "2.7.16",
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",

View File

@ -73,6 +73,7 @@
"vue-dompurify-html": "^4.1.4", "vue-dompurify-html": "^4.1.4",
"vue-i18n": "9.10.2", "vue-i18n": "9.10.2",
"vue-router": "4.4.5", "vue-router": "4.4.5",
"vue-signature-pad": "^3.0.2",
"vue-types": "^5.1.1", "vue-types": "^5.1.1",
"vue3-signature": "^0.2.4", "vue3-signature": "^0.2.4",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",

View File

@ -0,0 +1,51 @@
import request from '@/config/axios'
// 上线申请 VO
export interface OnlineApplicationVO {
id: number // 唯一主键
projectName: string // 产品名称
projectType: number // 项目类型
deptId: number // 申请部门
userId: number // 申请人
testCompletionDate: Date // 测试完成日期
onlineDate: Date // 申请上线日期
externalSystem: string // 上线系统是否涉及第三方系统(如:是/否)
precautions: string // 上线注意事项
emergencyManagement: string // 失败应急处理
applicantSign: string // 申请人签字
processInstanceId: string // 工作流编号
auditStatus: number // 审批状态
}
// 上线申请 API
export const OnlineApplicationApi = {
// 查询上线申请分页
getOnlineApplicationPage: async (params: any) => {
return await request.get({ url: `/tts/online-application/page`, params })
},
// 查询上线申请详情
getOnlineApplication: async (id: number) => {
return await request.get({ url: `/tts/online-application/get?id=` + id })
},
// 新增上线申请
createOnlineApplication: async (data: OnlineApplicationVO) => {
return await request.post({ url: `/tts/online-application/create`, data })
},
// 修改上线申请
updateOnlineApplication: async (data: OnlineApplicationVO) => {
return await request.put({ url: `/tts/online-application/update`, data })
},
// 删除上线申请
deleteOnlineApplication: async (id: number) => {
return await request.delete({ url: `/tts/online-application/delete?id=` + id })
},
// 导出上线申请 Excel
exportOnlineApplication: async (params) => {
return await request.download({ url: `/tts/online-application/export-excel`, params })
}
}

View File

@ -42,6 +42,8 @@ import Logger from '@/utils/Logger'
import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐患 import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐患
import VueSignaturePad from "vue-signature-pad";
// 创建实例 // 创建实例
const setupAll = async () => { const setupAll = async () => {
const app = createApp(App) const app = createApp(App)
@ -65,6 +67,7 @@ const setupAll = async () => {
await router.isReady() await router.isReady()
app.use(VueDOMPurifyHTML) app.use(VueDOMPurifyHTML)
app.use(VueSignaturePad);
app.mount('#app') app.mount('#app')
} }

View File

@ -849,6 +849,17 @@ const remainingRouter: AppRouteRecordRaw[] = [
}, },
component: () => import('@/views/task/components/ProjectTaskForm.vue') component: () => import('@/views/task/components/ProjectTaskForm.vue')
}, },
{
path: 'online/OnlineApplicationForm',
name: 'OnlineAppAdd',
meta: {
title: '上线新增',
noCache: true,
hidden: true,
activeMenu: '/project/online'
},
component: () => import('@/views/task/online/OnlineApplicationForm.vue')
},
] ]
}, },
{ {

View File

@ -50,7 +50,7 @@
<el-form-item label="合同状态" prop="quotationId"> <el-form-item label="合同状态" prop="quotationId">
<el-select v-model="formData.auditStatus" disabled clearable placeholder="请选择合同状态"> <el-select v-model="formData.auditStatus" disabled clearable placeholder="请选择合同状态">
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" v-for="dict in getIntDictOptions(DICT_TYPE.CRM_AUDIT_STATUS)"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
:value="dict.value" :value="dict.value"

View File

@ -74,58 +74,13 @@ const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // create - update - const formType = ref('') // create - update -
const formData = ref({ const formData = ref({
no: undefined, terminationDate: undefined,
customerId: undefined, terminationReason: undefined,
businessId: undefined, note: undefined,
invoiceTemplateId: undefined,
processInstanceId: undefined,
auditStatus: undefined,
ownerUserId: undefined,
expanderUserId: undefined,
pricingUserId: undefined,
signUserId: undefined,
signPhoneNumber: undefined,
signEmail: undefined,
signWechat: undefined,
paymentTerm: undefined,
creditMethod: undefined,
creditCalcCycle: undefined,
creditLimit: undefined,
partnerCompanyId: undefined,
deptId: undefined,
creator: undefined,
createTime: undefined,
updater: undefined,
onlinePrice: undefined,
offlinePrice: undefined,
totalPrice: undefined,
cooperationType: undefined, //
companyType: undefined, //
listingStatus: undefined, //
financingInfo: undefined, //
paidInCapital: undefined, //
insuredCount: undefined, //
establishmentDate: undefined, //
enterpriseType: undefined, //
businessStatus: undefined, //
defendantRecord: undefined, //
businessAbnormal: undefined, //
equityPledge: undefined, //
dishonestRecord: undefined, //
financingRecord: undefined, //
enforcementRecord: undefined, //
bBankName: undefined, //
bBankAccount: undefined, //
bLegalRepresentative: undefined, //
bBusinessLicenseNumber: undefined, //
bBusinessLicense: undefined //
}) })
const formRules = reactive({ const formRules = reactive({
// cooperationType: [{ required: true, message: '', trigger: 'change' }], terminationReason: [{ required: true, message: '终止原因不能为空', trigger: 'change' }],
// no: [{ required: true, message: '', trigger: 'blur' }], terminationDate: [{ required: true, message: '终止日期不能为空', trigger: 'blur' }],
// customerId: [{ required: true, message: 'id', trigger: 'change' }],
// businessId: [{ required: true, message: '', trigger: 'change' }],
// invoiceTemplateId: [{ required: true, message: 'Id', trigger: 'change' }]
}) })
const formRef = ref() // Ref const formRef = ref() // Ref

View File

@ -67,48 +67,48 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item label="被告记录" prop="defendantRecord"> <el-form-item label="被告记录" prop="defendantRecord">
<el-radio-group v-model="formData.defendantRecord" :disabled="true"> <el-radio-group v-model="formData.defendantRecord" :disabled="true">
<el-radio :label="true"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="经营异常" prop="abnormalService"> <el-form-item label="经营异常" prop="abnormalService">
<el-radio-group v-model="formData.abnormalService" :disabled="true"> <el-radio-group v-model="formData.abnormalService" :disabled="true">
<el-radio :label="true"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="股权出质" prop="equityPledge"> <el-form-item label="股权出质" prop="equityPledge">
<el-radio-group v-model="formData.equityPledge" :disabled="true"> <el-radio-group v-model="formData.equityPledge" :disabled="true">
<el-radio :label="true"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="失信记录" prop="dishonestyRecord"> <el-form-item label="失信记录" prop="dishonestyRecord">
<el-radio-group v-model="formData.dishonestyRecord" :disabled="true"> <el-radio-group v-model="formData.dishonestyRecord" :disabled="true">
<el-radio :label="true"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="融资记录" prop="financeRecord"> <el-form-item label="融资记录" prop="financeRecord">
<el-radio-group v-model="formData.financeRecord" :disabled="true"> <el-radio-group v-model="formData.financeRecord" :disabled="true">
<el-radio :label="true"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="被执行记录" prop="judgmentRecord"> <el-form-item label="被执行记录" prop="judgmentRecord">
<el-radio-group v-model="formData.judgmentRecord" :disabled="true"> <el-radio-group v-model="formData.judgmentRecord" :disabled="true">
<el-radio :label="true"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -276,7 +276,7 @@ watch(
) )
const onChangeAmount = async (amount: number) => { const onChangeAmount = async (amount: number) => {
formData.value.afterAmount = Number(formData.value.creditLimit) + Number(amount).toFixed(2); formData.value.afterAmount = Number(formData.value.creditLimit) + Number(Number(amount).toFixed(2));
} }
const onCustomerChange = async (customerId: string) => { const onCustomerChange = async (customerId: string) => {

View File

@ -59,7 +59,7 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="附件" prop="fileUrls"> <el-form-item label="附件" prop="fileUrls">
<UploadFile v-model="formData.fileUrls" /> <UploadFile v-model="formData.fileUrls" :limit="1" />
</el-form-item> </el-form-item>
</el-col> </el-col>

View File

@ -36,14 +36,14 @@
<el-input v-model="formData.content" :rows="3" type="textarea" /> <el-input v-model="formData.content" :rows="3" type="textarea" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="24">
<el-form-item label="图片" prop="picUrls"> <el-form-item label="图片" prop="picUrls">
<UploadImgs v-model="formData.picUrls" class="min-w-80px" /> <UploadImgs v-model="formData.picUrls" class="min-w-80px" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="24">
<el-form-item label="附件" prop="fileUrls"> <el-form-item label="附件" prop="fileUrls">
<UploadFile v-model="formData.fileUrls" class="min-w-80px" /> <UploadFile v-model="formData.fileUrls" :limit="1" class="min-w-80px" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24" v-if="formData.bizType == BizTypeEnum.CRM_CUSTOMER"> <el-col :span="24" v-if="formData.bizType == BizTypeEnum.CRM_CUSTOMER">

View File

@ -164,7 +164,7 @@ const getList = async () => {
const previewPic = (val) => { const previewPic = (val) => {
show.value = true show.value = true
urlList.value = val.split(',') urlList.value = val
} }
/** 添加/修改操作 */ /** 添加/修改操作 */
@ -187,15 +187,16 @@ const handleDelete = async (id: number) => {
} }
// //
const router = useRouter() //
const previewFile = (fileUrls) => { const previewFile = (fileUrls) => {
// // fileUrls URL // // fileUrls URL
fileUrls = fileUrls + ''
if (!fileUrls) { if (!fileUrls) {
message.error('没有附件'); message.error('没有附件');
return; return;
} }
// //
const router = useRouter() //
const fileExtension = fileUrls.split('.').pop().toLowerCase(); const fileExtension = fileUrls.split('.').pop().toLowerCase();
router.push({ router.push({
name: 'FileTemplatePreview', name: 'FileTemplatePreview',

View File

@ -10,7 +10,7 @@
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8" v-if="!route.query.taskId">
<el-form-item label="选择商机" prop="businessId"> <el-form-item label="选择商机" prop="businessId">
<el-select v-model="formData.businessId" disabled clearable @change="onBusinessChange"> <el-select v-model="formData.businessId" disabled clearable @change="onBusinessChange">
<el-option <el-option

View File

@ -16,7 +16,7 @@
</el-table-column> </el-table-column>
<el-table-column label="团队奖金" align="center" prop="bonusAmount" /> <el-table-column label="团队奖金" align="center" prop="bonusAmount" />
<el-table-column label="所得奖金" align="center" prop="bonusIssueDate" /> <el-table-column label="所得奖金" align="center" prop="bonusIssueDate" />
<el-table-column label="操作" align="center" min-width="120px"> <el-table-column label="操作" align="center" min-width="120px" v-if="!type">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
@ -29,7 +29,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-row justify="center" class="mt-3" > <el-row justify="center" class="mt-3" v-if="!type">
<el-button @click="openForm" round>+ 添加</el-button> <el-button @click="openForm" round>+ 添加</el-button>
</el-row> </el-row>
<!-- <el-button <!-- <el-button
@ -67,6 +67,7 @@ const message = useMessage() // 消息弹窗
const { t } = useI18n() // const { t } = useI18n() //
const props = defineProps({ const props = defineProps({
id: propTypes.number.def(undefined), id: propTypes.number.def(undefined),
type: propTypes.number.def(undefined),
userOptions: propTypes.object.def([]), userOptions: propTypes.object.def([]),
}) })
const loading = ref(true) // const loading = ref(true) //

View File

@ -45,7 +45,7 @@
:formatter="dateFormatter" :formatter="dateFormatter"
width="180px" width="180px"
/> --> /> -->
<el-table-column label="操作" align="center" min-width="120px"> <el-table-column label="操作" align="center" min-width="120px" v-if="!type">
<template #default="scope"> <template #default="scope">
<el-button <el-button
link link
@ -66,7 +66,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-row justify="center" class="mt-3" > <el-row justify="center" class="mt-3" v-if="!type">
<el-button @click="openForm('create')" round>+ 添加</el-button> <el-button @click="openForm('create')" round>+ 添加</el-button>
</el-row> </el-row>
<!-- 分页 --> <!-- 分页 -->
@ -97,6 +97,7 @@ const message = useMessage() // 消息弹窗
const { t } = useI18n() // const { t } = useI18n() //
const props = defineProps({ const props = defineProps({
id: propTypes.number.def(undefined), id: propTypes.number.def(undefined),
type: propTypes.number.def(undefined),
userId: propTypes.number.def(undefined), userId: propTypes.number.def(undefined),
name: propTypes.number.def(undefined), name: propTypes.number.def(undefined),
userOptions: propTypes.object.def([]), userOptions: propTypes.object.def([]),

View File

@ -0,0 +1,179 @@
<template>
<ContentWrap>
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="产品名称" prop="projectName">
<el-input v-model="formData.projectName" placeholder="请输入产品名称" />
</el-form-item>
<el-form-item label="项目类型" prop="projectType">
<el-select v-model="formData.projectType" placeholder="请选择项目类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TTS_PROJECT_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="申请部门" prop="deptId">
<el-input v-model="formData.deptId" placeholder="请输入申请部门" />
</el-form-item>
<el-form-item label="申请人" prop="userId">
<el-input v-model="formData.userId" placeholder="请输入申请人" />
</el-form-item>
<el-form-item label="测试完成日期" prop="testCompletionDate">
<el-date-picker
v-model="formData.testCompletionDate"
type="date"
value-format="x"
placeholder="选择测试完成日期"
/>
</el-form-item>
<el-form-item label="申请上线日期" prop="onlineDate">
<el-date-picker
v-model="formData.onlineDate"
type="date"
value-format="x"
placeholder="选择申请上线日期"
/>
</el-form-item>
<el-form-item label="上线系统是否涉及第三方系统" prop="externalSystem">
<el-input v-model="formData.externalSystem" placeholder="请输入上线系统是否涉及第三方系统(如:是/否)" />
</el-form-item>
<el-form-item label="上线注意事项" prop="precautions">
<el-input v-model="formData.precautions" placeholder="请输入上线注意事项" />
</el-form-item>
<el-form-item label="失败应急处理" prop="emergencyManagement">
<el-input v-model="formData.emergencyManagement" placeholder="请输入失败应急处理" />
</el-form-item>
<el-form-item label="申请人签字" prop="applicantSign">
<Ceshi />
</el-form-item>
<!-- <el-form-item label="工作流编号" prop="processInstanceId">
<el-input v-model="formData.processInstanceId" placeholder="请输入工作流编号" />
</el-form-item>
<el-form-item label="审批状态" prop="auditStatus">
<el-radio-group v-model="formData.auditStatus">
<el-radio value="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item> -->
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</ContentWrap>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { OnlineApplicationApi, OnlineApplicationVO } from '@/api/task/online'
import Ceshi from './ceshi.vue'
/** 上线申请 表单 */
defineOptions({ name: 'OnlineApplicationForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
projectName: undefined,
projectType: undefined,
deptId: undefined,
userId: undefined,
testCompletionDate: undefined,
onlineDate: undefined,
externalSystem: undefined,
precautions: undefined,
emergencyManagement: undefined,
applicantSign: undefined,
processInstanceId: undefined,
auditStatus: undefined
})
const formRules = reactive({
projectName: [{ required: true, message: '产品名称不能为空', trigger: 'blur' }],
projectType: [{ required: true, message: '项目类型不能为空', trigger: 'change' }],
deptId: [{ required: true, message: '申请部门不能为空', trigger: 'blur' }],
userId: [{ required: true, message: '申请人不能为空', trigger: 'blur' }],
testCompletionDate: [{ required: true, message: '测试完成日期不能为空', trigger: 'blur' }],
onlineDate: [{ required: true, message: '申请上线日期不能为空', trigger: 'blur' }],
externalSystem: [{ required: true, message: '上线系统是否涉及第三方系统(如:是/否)不能为空', trigger: 'blur' }],
precautions: [{ required: true, message: '上线注意事项不能为空', trigger: 'blur' }],
emergencyManagement: [{ required: true, message: '失败应急处理不能为空', trigger: 'blur' }],
applicantSign: [{ required: true, message: '申请人签字不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await OnlineApplicationApi.getOnlineApplication(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as OnlineApplicationVO
if (formType.value === 'create') {
await OnlineApplicationApi.createOnlineApplication(data)
message.success(t('common.createSuccess'))
} else {
await OnlineApplicationApi.updateOnlineApplication(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
projectName: undefined,
projectType: undefined,
deptId: undefined,
userId: undefined,
testCompletionDate: undefined,
onlineDate: undefined,
externalSystem: undefined,
precautions: undefined,
emergencyManagement: undefined,
applicantSign: undefined,
processInstanceId: undefined,
auditStatus: undefined
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,185 @@
<template>
<div class="handwritten-name-wrap">
<el-button plain @click="handleClick">
手写签名
</el-button>
<div class="img-wrap">
<el-image :src="imgSrc" alt="" v-if="imgSrc" />
</div>
<vxe-modal
v-model="panelVisible"
title="手写签名"
width="600"
height="400"
size="large"
:destroy-on-close="true"
class="signNameModel"
>
<slot>
<div class="signWrap">
<VueSignaturePad
width="100%"
height="100%"
ref="signaturePad"
:options="options"
/>
<footer>
<div class="gtnGroup">
<el-button type="primary" size="mini" @click="undo"></el-button>
<el-button type="primary" size="mini" style="margin-left:20px" @click="clear"></el-button>
<el-button type="primary" size="mini" style="margin-left:20px" @click="save"></el-button>
</div>
<div class="otherSet">
<div class="penTxt">笔刷大小</div>
<div class="circleWrap" :class="{ active: isActive1 }" @click="selSize(1)"><b class="b1"></b></div>
<div class="circleWrap" :class="{ active: isActive2 }" @click="selSize(2)"><b class="b2"></b></div>
<div class="circleWrap" :class="{ active: isActive3 }" @click="selSize(3)"><b class="b3"></b></div>
</div>
</footer>
</div>
</slot>
</vxe-modal>
</div>
</template>
<script>
export default {
data(){
return {
panelVisible:false,
panelTitle:"",
options: {
penColor: "#000",
minWidth: 1, //
maxWidth: 1, //
},
isActive1:true,
isActive2:false,
isActive3:false,
imgSrc:"",
}
},
methods: {
//
handleClick(){
this.panelVisible=true;
this.isActive1=true;
this.isActive2=false;
this.isActive3=false;
this.options = {
penColor: "#000",
minWidth: 1,
maxWidth: 1,
}
},
//
undo(){
this.$refs.signaturePad.undoSignature();
},
//
clear(){
this.$refs.signaturePad.clearSignature();
},
//
save(){
console.log( this.$refs.signaturePad.saveSignature() );
const { isEmpty, data } = this.$refs.signaturePad.saveSignature();
this.imgSrc = data;
this.panelVisible = false;
},
//
selSize(val){
this.options = {
penColor: "#000",
minWidth: val,
maxWidth: val,
};
if(val==1){
this.isActive1=true;
this.isActive2=false;
this.isActive3=false;
}else if(val==2){
this.isActive1=false;
this.isActive2=true;
this.isActive3=false;
}else if(val==3){
this.isActive1=false;
this.isActive2=false;
this.isActive3=true;
}
}
},
}
</script>
<style lang="scss">
.handwritten-name-wrap{
.img-wrap{
width:100%;
height:164px;
margin-top:2px;
border:1px solid #ccc;
img{
width:70%;
height:100%;
}
}
.signWrap{
height:100%;
display:flex;
flex-direction:column;
justify-content:center;
.signName{
flex:1;
border-top:1px solid #ccc;
}
footer{
height:40px;
border-top:1px solid #ccc;
display:flex;
justify-content: space-between;
align-items: center;
.gtnGroup{
width:50%;
margin-left: 20px;
}
.otherSet{
width:50%;
display:flex;
align-items: center;
.penTxt{
width:70px;
}
.selSize{
width:70px;
}
.el-select__caret{
position: absolute;
right: -3px;
}
.b1,.b2,.b3{
display: inline-block;
background: #000;
border-radius: 50%;
}
.circleWrap{
display: flex;
justify-content: center;
align-items: center;
width:18px;
height:18px;
cursor:pointer;
margin-right:20px;
}
.active{ border:1px dashed #0074d9; }
.b1{width:4px;height:4px}
.b2{width:6px;height:6px}
.b3{width:8px;height:8px}
}
}
}
}
.signNameModel{
.vxe-modal--content{
padding:0 !important;
}
}
</style>

View File

@ -0,0 +1,242 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="100px"
>
<el-form-item label="产品名称" prop="projectName">
<el-input
v-model="queryParams.projectName"
placeholder="请输入产品名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="申请部门" prop="deptId">
<el-input
v-model="queryParams.deptId"
placeholder="请输入申请部门"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="申请上线日期" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openFormAdd('create')"
v-hasPermi="['tts:online-application:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['tts:online-application:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="唯一主键" align="center" prop="id" />
<el-table-column label="产品名称" align="center" prop="projectName" />
<!-- <el-table-column label="项目类型" align="center" prop="projectType">
<template #default="scope">
<dict-tag :type="DICT_TYPE.TTS_PROJECT_TYPE" :value="scope.row.projectType" />
</template>
</el-table-column> -->
<el-table-column label="申请人" align="center" prop="userId" />
<el-table-column label="申请部门" align="center" prop="deptId" />
<el-table-column label="测试完成日期" align="center" prop="testCompletionDate" />
<el-table-column label="申请上线日期" align="center" prop="onlineDate" />
<el-table-column label="上线系统是否涉及第三方系统" align="center" prop="externalSystem" />
<!-- <el-table-column label="上线注意事项" align="center" prop="precautions" />
<el-table-column label="失败应急处理" align="center" prop="emergencyManagement" />
<el-table-column label="申请人签字" align="center" prop="applicantSign" />
<el-table-column label="工作流编号" align="center" prop="processInstanceId" />
<el-table-column label="审批状态" align="center" prop="auditStatus" />
<el-table-column label="创建者" align="center" prop="creator" /> -->
<!-- <el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="更新者" align="center" prop="updater" />
<el-table-column
label="更新时间"
align="center"
prop="updateTime"
:formatter="dateFormatter"
width="180px"
/> -->
<el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['tts:online-application:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['tts:online-application:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<OnlineApplicationForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { OnlineApplicationApi, OnlineApplicationVO } from '@/api/task/online'
import OnlineApplicationForm from './OnlineApplicationForm.vue'
/** 上线申请 列表 */
defineOptions({ name: 'OnlineApplication' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<OnlineApplicationVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
projectName: undefined,
projectType: undefined,
deptId: undefined,
userId: undefined,
testCompletionDate: [],
onlineDate: [],
externalSystem: undefined,
precautions: undefined,
emergencyManagement: undefined,
applicantSign: undefined,
processInstanceId: undefined,
auditStatus: undefined,
creator: undefined,
createTime: [],
updater: undefined,
updateTime: []
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await OnlineApplicationApi.getOnlineApplicationPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const { push } = useRouter()
const router = useRouter() //
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
const openFormAdd = () => {
push({ name: 'OnlineAppAdd' })
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await OnlineApplicationApi.deleteOnlineApplication(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await OnlineApplicationApi.exportOnlineApplication(queryParams)
download.excel(data, '上线申请.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -16,7 +16,7 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item label="项目级别" prop="projectLevel"> <el-form-item label="项目级别" prop="projectLevel">
<el-select v-model="formData.projectLevel" disabled placeholder="请输入项目级别"> <el-select v-model="formData.projectLevel" :disabled="formType" placeholder="请输入项目级别">
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TTS_PROJECT_LEVEL)" v-for="dict in getIntDictOptions(DICT_TYPE.TTS_PROJECT_LEVEL)"
:key="dict.value" :key="dict.value"
@ -28,7 +28,7 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="项目类型" prop="projectType"> <el-form-item label="项目类型" prop="projectType">
<el-select v-model="formData.projectType" disabled placeholder="请选择项目类型"> <el-select v-model="formData.projectType" :disabled="formType" placeholder="请选择项目类型">
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.TTS_PROJECT_TYPE)" v-for="dict in getIntDictOptions(DICT_TYPE.TTS_PROJECT_TYPE)"
:key="dict.value" :key="dict.value"
@ -40,14 +40,14 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="项目名称" prop="name"> <el-form-item label="项目名称" prop="name">
<el-input v-model="formData.name" disabled placeholder="请输入项目名称" /> <el-input v-model="formData.name" :disabled="formType" placeholder="请输入项目名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="项目负责人" prop="userId"> <el-form-item label="项目负责人" prop="userId">
<el-select <el-select
disabled
v-model="formData.userId" v-model="formData.userId"
:disabled="formType"
placeholder="请选择项目负责人" placeholder="请选择项目负责人"
filterable filterable
> >
@ -62,8 +62,8 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="项目开始日期" prop="startDate"> <el-form-item label="项目开始日期" prop="startDate">
<el-date-picker <el-date-picker
disabled :disabled="formType"
v-model="formData.startDate" v-model="formData.startDate"
style="width: 100%" style="width: 100%"
type="date" type="date"
@ -74,8 +74,8 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="项目结束日期" prop="endDate"> <el-form-item label="项目结束日期" prop="endDate">
<el-date-picker <el-date-picker
disabled :disabled="formType"
v-model="formData.endDate" v-model="formData.endDate"
style="width: 100%" style="width: 100%"
type="date" type="date"
@ -87,7 +87,7 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item label="归属部门" prop="deptId"> <el-form-item label="归属部门" prop="deptId">
<el-tree-select <el-tree-select
disabled :disabled="formType"
v-model="formData.deptId" v-model="formData.deptId"
:data="deptTree" :data="deptTree"
:props="defaultProps" :props="defaultProps"
@ -97,22 +97,30 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8" v-if="formType"> <el-col :span="8">
<el-form-item label="立项奖金评估" prop="bonusEvaluation"> <el-form-item label="立项奖金评估" prop="bonusEvaluation">
<el-radio-group v-model="formData.bonusEvaluation">
<el-switch <el-switch
disabled
v-model="formData.bonusEvaluation" v-model="formData.bonusEvaluation"
class="ml-2" class="ml-2"
/> />
</el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8" v-if="formData.bonusEvaluation"> <el-col :span="8" v-if="formData.bonusEvaluation">
<el-form-item label="立项奖金金额" prop="bonusAmount"> <el-form-item label="立项奖金金额" prop="bonusAmount">
<el-input v-model="formData.bonusAmount" disabled placeholder="请输入奖金评估描述" /> <el-input v-model="formData.bonusAmount" disabled oninput="value=value.match(/^\d+(?:\.\d{0,2})?/)" placeholder="请输入奖金评估描述" />
</el-form-item>
</el-col>
<el-col :span="8" v-if="formData.bonusEvaluation">
<el-form-item label="项目进度(%" prop="progress">
<el-input v-model="formData.progress" disabled oninput = "value=value.replace(/[^\d]/g,'')" placeholder="请输入奖金评估描述" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="项目附件" prop="attachment"> <el-form-item label="项目附件" prop="attachment">
<UploadFile v-model="formData.attachment" :limit="1" :fileType="['doc','docx']"/> <UploadFile v-model="formData.attachment" :disabled="!!formType" :limit="1" :fileType="['doc','docx']"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -122,17 +130,17 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="项目背景" prop="background"> <el-form-item label="项目背景" prop="background">
<el-input v-model="formData.background" disabled type="textarea" :rows="5" placeholder="请输入项目背景" /> <el-input v-model="formData.background" type="textarea" :disabled="formType" :rows="5" placeholder="请输入项目背景" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="项目简介" prop="introduction"> <el-form-item label="项目简介" prop="introduction">
<el-input v-model="formData.introduction" disabled type="textarea" :rows="5" placeholder="请输入项目简介" /> <el-input v-model="formData.introduction" type="textarea" :disabled="formType" :rows="5" placeholder="请输入项目简介" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="项目预期" prop="expectation"> <el-form-item label="项目预期" prop="expectation">
<el-input v-model="formData.expectation" disabled type="textarea" :rows="5" placeholder="请输入项目预期" /> <el-input v-model="formData.expectation" type="textarea" :disabled="formType" :rows="5" placeholder="请输入项目预期" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- <el-col :span="8"> <!-- <el-col :span="8">
@ -158,31 +166,28 @@
</ContentWrap> </ContentWrap>
<el-row v-if="formData.auditStatus == 2"> <el-row v-if="formData.auditStatus == 2">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="系数总和" prop="expectation"> <el-form-item label="系数总和" prop="">
<el-input v-model="formData.expectation" disabled placeholder="系数总和" /> <el-input v-model="coefficient" disabled placeholder="系数总和" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="团队奖金" prop="expectation"> <el-form-item label="团队奖金" prop="">
<el-input v-model="formData.expectation" disabled placeholder="团队奖金" /> <el-input v-model="teamAmount" disabled placeholder="团队奖金" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<ContentWrap style="border: none;font-weight: 700" v-if="formData.auditStatus == 2"> <ContentWrap style="border: none;font-weight: 700" v-if="formData.auditStatus == 2">
团队成员 团队成员
</ContentWrap> </ContentWrap>
<Bonus ref="formRef" v-if="formData.auditStatus == 2" /> <Bonus ref="formRef" v-if="formData.auditStatus == 2" :userOptions="userOptions" :type="formType" :id="formData.id" @success="getData" />
<ContentWrap style="border: none;font-weight: 700" v-if="formData.auditStatus == 2"> <ContentWrap style="border: none;font-weight: 700" v-if="formData.auditStatus == 2">
任务信息 任务信息
</ContentWrap> </ContentWrap>
<Task ref="taskRef" v-if="formData.auditStatus == 2" /> <Task ref="taskRef" v-if="formData.auditStatus == 2" :userOptions="userOptions" :type="formType" :id="formData.id" :userId="formData.userId" :name="formData.name" />
</el-form> </el-form>
<div style="text-align: right" v-if="!type">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="goBack"> </el-button>
</div>
</ContentWrap> </ContentWrap>
@ -211,10 +216,22 @@ const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
const message = useMessage() // const message = useMessage() //
const deptTree = ref() // const deptTree = ref() //
const routeId = ref('') const routeId = ref('')
const teamAmount = ref('')
const coefficient = ref('')
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('') // const dialogTitle = ref('') //
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // create - update - const formType = ref('') // create - update -
const validateProgress = (_: any, __: any, callback: any) => {
const num = Number(formData.value.progress)
if (num <= 0 || num >100) {
callback(new Error('请输入正确的项目进度'))
return
}
callback()
}
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
projectCode: undefined, projectCode: undefined,
@ -244,7 +261,8 @@ const formRules = reactive({
endDate: [{ required: true, message: '项目结束日期不能为空', trigger: 'blur' }], endDate: [{ required: true, message: '项目结束日期不能为空', trigger: 'blur' }],
attachment: [{ required: true, message: '项目附件不能为空', trigger: 'blur' }], attachment: [{ required: true, message: '项目附件不能为空', trigger: 'blur' }],
background: [{ required: true, message: '项目背景不能为空', trigger: 'blur' }], background: [{ required: true, message: '项目背景不能为空', trigger: 'blur' }],
introduction: [{ required: true, message: '项目简介不能为空', trigger: 'blur' }] introduction: [{ required: true, message: '项目简介不能为空', trigger: 'blur' }],
progress: [{ validator: validateProgress, trigger: 'blur' }],
}) })
const formRef = ref() // Ref const formRef = ref() // Ref
@ -294,6 +312,17 @@ const goBack = ()=> {
proxy.$router.go(-1) proxy.$router.go(-1)
} }
const getData = (val) => {
let amount = 0
let coefficientNum = 0
val.forEach( item => {
amount = amount + item.bonusAmount
coefficientNum = coefficientNum + item.bonusPercentage
})
coefficient.value = (coefficientNum * 100).toFixed(2) + '%'
teamAmount.value = amount
}
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { formData.value = {