预立案登记页面功能修改、利益冲突检索页面接口对接

This commit is contained in:
雷校云
2025-12-16 17:49:31 +08:00
parent 81fd3b2144
commit 45a7a166c5
7 changed files with 635 additions and 570 deletions

View File

@@ -0,0 +1,46 @@
import request from '@/utils/request'
const AUTH_BASE_URL = '/api2'
/*
* 投标登记
* */
// 新增投标登记
export const BusinessBid = (data: any) => {
const formData = new FormData()
formData.append('BiddingUnit', data.BiddingUnit)
formData.append('ProjectName', data.ProjectName)
formData.append('times', data.times)
formData.append('BiddingAnnouncement', data.BiddingAnnouncement)
formData.append('personincharge', data.personincharge)
formData.append('user_id', data.user_id)
return request({
url: `${AUTH_BASE_URL}/business/bid`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 投标登记展示
export const BusinessBiddetail = (data: any) => {
const formData = new FormData()
formData.append('page', data.pageNum)
formData.append('per_page', data.pageSize)
if (data.times && data.times.length) {
formData.append('times', data.times[0])
formData.append('end_time', data.times[1])
}
formData.append('client_username', data.client_username)
formData.append('party_username', data.party_username)
return request({
url: `${AUTH_BASE_URL}/business/biddetail`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}

View File

@@ -8,15 +8,14 @@ const AUTH_BASE_URL = '/api2'
// 新增立项登记
export const BusinessProject = (data: any) => {
const formData = new FormData()
formData.append('type', data.type)
formData.append('type', data.type.split(',')[0])
formData.append('ContractNo', data.ContractNo)
formData.append('times', data.times)
formData.append('client_info', data.client_info)
formData.append('party_info', data.party_info)
formData.append('description', data.description)
formData.append('responsiblefor', data.responsiblefor)
formData.append('charge', data.charge)
formData.append('contract', data.contract)
formData.append('personincharge', data.personincharge)
formData.append('user_id', data.user_id)
return request({
url: `${AUTH_BASE_URL}/business/project`,
method: 'post',
@@ -27,13 +26,33 @@ export const BusinessProject = (data: any) => {
})
}
// 审批分页接口
export const UserRoxyexhibition = (data: any) => {
// 立案登记类型查询
export const BusinessProjectquerytype = (type: string) => {
const formData = new FormData()
formData.append('page', data.pageNum)
formData.append('per_page', data.pageSize)
formData.append('type', type)
return request({
url: `${AUTH_BASE_URL}/user/roxyexhibition`,
url: `${AUTH_BASE_URL}/business/projectquerytype`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 立项登记展示
export const BusinessProjectdetail = (data: any) => {
const formData = new FormData()
formData.append('page', data.pageNum)
formData.append('per_page', data.pageSize)
if (data.times && data.times.length) {
formData.append('times', data.times[0])
formData.append('end_time', data.times[1])
}
formData.append('client_username', data.client_username)
formData.append('party_username', data.party_username)
return request({
url: `${AUTH_BASE_URL}/business/projectdetail`,
method: 'post',
data: formData,
headers: {

View File

@@ -44,3 +44,11 @@ export const BusinessRegisterdetail = (data: any) => {
}
})
}
// 预立案登记列表接口
export const BusinessRegistrationlist = () => {
return request({
url: `${AUTH_BASE_URL}/business/registrationlist`,
method: 'post'
})
}

View File

@@ -0,0 +1,284 @@
<template>
<div class="pre-registration-form">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="auto"
label-position="top"
>
<el-form-item label="预立案" prop="user_id">
<el-select v-model="formData.user_id" placeholder="请选择预立案">
<el-option
v-for="(item, index) in userIdList"
:key="index"
:label="
JSON.parse(item.party_username)
.map((item1: any) => item1.name)
.join('')
"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="项目名称" prop="ProjectName">
<el-input v-model="formData.ProjectName" placeholder="请输入" />
</el-form-item>
<el-form-item label="申请日期" prop="times">
<el-date-picker
v-model="formData.times"
type="date"
placeholder="请选择立项日期时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
<div class="section">
<h2>招标单位信息</h2>
<div class="table-actions">
<el-button type="primary" @click="addOpponent">
<el-icon><Plus /></el-icon>
新增一项
</el-button>
</div>
<el-table
:data="formData.BiddingUnit"
border
style="width: 100%"
class="opponent-table"
@selection-change="handleOpponentSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="index" label="序号" width="80" align="center" />
<el-table-column prop="name" label="自然人姓名/法人名称" min-width="200">
<template #default="scope">
<el-form-item
:prop="'BiddingUnit.' + scope.$index + '.name'"
:rules="formRules.opponentName"
>
<el-input v-model="scope.row.name" placeholder="请输入" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号码/统一代码" min-width="250">
<template #default="scope">
<el-form-item
:prop="'BiddingUnit.' + scope.$index + '.idNumber'"
:rules="formRules.opponentIdNumber"
>
<el-input v-model="scope.row.idNumber" placeholder="请输入" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="copyOpponent(scope.row)">
复制
</el-button>
<el-button type="danger" size="small" @click="deleteOpponent(scope.$index)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-form-item label="招标公告" prop="BiddingAnnouncement">
<el-upload
class="avatar-uploader"
action="#"
:auto-upload="false"
:show-file-list="false"
:on-change="(file) => handleFileSelect(file, 'BiddingAnnouncement')"
:before-upload="handleBeforeUpload"
>
<div v-if="formData.BiddingAnnouncement" class="upload-preview">
<span>{{ formData.BiddingAnnouncement.name }}</span>
<el-button type="danger" size="small" @click.stop="removeFile('BiddingAnnouncement')">
删除
</el-button>
</div>
<el-button v-else size="small" type="primary">点击选择文件</el-button>
</el-upload>
</el-form-item>
<el-form-item label="代办负责人" prop="personincharge">
<el-select v-model="formData.personincharge" placeholder="请选择代办负责人">
<el-option
v-for="item in UndertakerList"
:key="item.id"
:label="item.username"
:value="item.username"
/>
</el-select>
</el-form-item>
<!-- 提交按钮 -->
<!-- <div class="form-actions">-->
<!-- <el-button type="primary" @click="handleSubmit">提交</el-button>-->
<!-- <el-button @click="handleSaveDraft">暂存</el-button>-->
<!-- </div>-->
</el-form>
</div>
</template>
<script lang="ts" setup>
import { Plus } from '@element-plus/icons-vue'
import { UserPersonneldisplay } from '@/api/calibration/personnelManagement'
import { ElMessage } from 'element-plus'
import { BusinessRegistrationlist } from '@/api/calibration/preRegistration'
const formRef = ref()
// 表单数据
const formData = reactive<any>({
user_id: '',
ProjectName: '',
times: '',
BiddingUnit: [{ index: 1, name: '', idNumber: '' }],
BiddingAnnouncement: undefined,
personincharge: ''
})
const UndertakerList = ref<any[]>([])
const userIdList = ref<any[]>([])
// 选择的相对方
const selectedOpponents = ref<any[]>([])
const formRules = reactive<any>({
user_id: [{ required: true, message: '请选择预立案', trigger: 'change' }],
ProjectName: [{ required: true, message: '请输入', trigger: 'change' }],
times: [{ required: true, message: '请选择预立案日期', trigger: 'change' }],
opponentName: [{ required: true, message: '请输入姓名/法人名称', trigger: 'blur' }],
opponentIdNumber: [{ required: true, message: '请输入身份证号码/统一代码', trigger: 'blur' }],
BiddingAnnouncement: [{ required: true, message: '请选择招标公告', trigger: 'blur' }],
personincharge: [{ required: true, message: '请选择审核人', trigger: 'blur' }]
})
// 处理相对方选择
const handleOpponentSelectionChange = (selection: any[]) => {
selectedOpponents.value = selection
}
// 新增相对方
const addOpponent = () => {
const newIndex = formData.BiddingUnit.length + 1
formData.BiddingUnit.push({ index: newIndex, name: '', idNumber: '' })
}
// 删除相对方
const deleteOpponent = (index: number) => {
if (formData.BiddingUnit.length > 1) {
formData.BiddingUnit.splice(index, 1)
// 更新序号
formData.BiddingUnit.forEach((opponent: any, idx: number) => {
opponent.index = idx + 1
})
} else {
ElMessage.warning('至少需要保留一个招标单位')
}
}
// 复制相对方
const copyOpponent = (opponent: any) => {
const newIndex = formData.BiddingUnit.length + 1
formData.BiddingUnit.push({ ...opponent, index: newIndex })
}
function handleFileSelect(file: any, field: string): void {
// 将文件对象保存到表单数据中
formData[field] = file.raw // file.raw 是实际的 File 对象
formRef.value.clearValidate(field)
ElMessage.success('文件选择成功')
}
function handleBeforeUpload(file: File): boolean {
// 可以在这里添加文件类型和大小的校验
const isLt10M = file.size / 1024 / 1024 < 10
if (!isLt10M) {
ElMessage.error('上传文件大小不能超过 10MB!')
return false
}
return true
}
function removeFile(field: string): void {
formData[field] = undefined
ElMessage.success('文件已删除')
}
const DepartmentList = () => {
UserPersonneldisplay().then((res: any) => {
UndertakerList.value = res.data
})
}
const onBusinessRegistrationlist = () => {
BusinessRegistrationlist().then((res: any) => {
console.log(res, 'res')
userIdList.value = res.data
})
}
onMounted(() => {
onBusinessRegistrationlist()
DepartmentList()
})
const getForm = () => {
return formData
}
const submit = (): Promise<boolean> => {
return new Promise((resolve, reject) => {
formRef.value?.validate((valid: boolean) => {
if (valid) {
// 验证招标单位至少存在一个
if (formData.BiddingUnit.length === 0) {
ElMessage.error('至少需要存在一个招标单位')
reject(false)
return
}
resolve(true)
} else {
ElMessage.error('请完善必填信息')
reject(false)
}
})
})
}
defineExpose({
submit,
getForm
})
</script>
<style scoped lang="scss">
.pre-registration-form {
width: 100%;
height: 600px;
padding-right: 20px;
overflow: hidden;
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.3);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.5);
}
}
.section {
display: flex;
flex-direction: column;
gap: 20px;
margin-bottom: 20px;
}
</style>

View File

@@ -7,13 +7,27 @@
label-width="auto"
label-position="top"
>
<el-form-item label="项目类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择项目类型">
<el-form-item label="预立案" prop="user_id">
<el-select v-model="formData.user_id" placeholder="请选择预立案">
<el-option
v-for="item in UndertakerList"
:key="item.id"
:label="item.username"
:value="item.username"
v-for="(item, index) in userIdList"
:key="index"
:label="
JSON.parse(item.party_username)
.map((item1: any) => item1.name)
.join('')
"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="项目类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择项目类型" @change="typeChange">
<el-option
v-for="(item, index) in typeList"
:key="index"
:label="item.name"
:value="`${item.name},${item.value}`"
/>
</el-select>
</el-form-item>
@@ -30,123 +44,6 @@
style="width: 100%"
/>
</el-form-item>
<div class="section">
<h2>委托人信息</h2>
<div class="table-actions">
<el-button type="primary" @click="addClient">
<el-icon><Plus /></el-icon>
新增一项
</el-button>
<el-button type="danger" @click="batchDeleteClients">
<el-icon><Delete /></el-icon>
批量删除
</el-button>
</div>
<el-table
:data="formData.client_info"
border
style="width: 100%"
class="client-table"
@selection-change="handleClientSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="index" label="序号" width="80" align="center" />
<el-table-column prop="name" label="自然人姓名/法人名称" min-width="200">
<template #default="scope">
<el-form-item
:prop="'client_info.' + scope.$index + '.name'"
:rules="formRules.clientName"
>
<el-input v-model="scope.row.name" placeholder="请输入" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号码/统一代码" min-width="250">
<template #default="scope">
<el-form-item
:prop="'client_info.' + scope.$index + '.idNumber'"
:rules="formRules.clientIdNumber"
>
<el-input v-model="scope.row.idNumber" placeholder="请输入" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="copyClient(scope.row)">复制</el-button>
<el-button type="danger" size="small" @click="deleteClient(scope.$index)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="section">
<h2>相对方信息</h2>
<div class="table-actions">
<el-button type="primary" @click="addOpponent">
<el-icon><Plus /></el-icon>
新增一项
</el-button>
<el-button type="danger">
<el-icon><Delete /></el-icon>
批量删除
</el-button>
</div>
<el-table
:data="formData.party_info"
border
style="width: 100%"
class="opponent-table"
@selection-change="handleOpponentSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="index" label="序号" width="80" align="center" />
<el-table-column prop="name" label="自然人姓名/法人名称" min-width="200">
<template #default="scope">
<el-form-item
:prop="'party_info.' + scope.$index + '.name'"
:rules="formRules.opponentName"
>
<el-input v-model="scope.row.name" placeholder="请输入" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="idNumber" label="身份证号码/统一代码" min-width="250">
<template #default="scope">
<el-form-item
:prop="'party_info.' + scope.$index + '.idNumber'"
:rules="formRules.opponentIdNumber"
>
<el-input v-model="scope.row.idNumber" placeholder="请输入" style="width: 100%" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template #default="scope">
<el-button type="primary" size="small" @click="copyOpponent(scope.row)">
复制
</el-button>
<el-button type="danger" size="small" @click="deleteOpponent(scope.$index)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-form-item label="描述" prop="description">
<el-input
v-model="formData.description"
type="textarea"
placeholder="描述"
:rows="4"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="负责人" prop="responsiblefor">
<el-select v-model="formData.responsiblefor" placeholder="请选择负责人">
<el-option
@@ -160,18 +57,27 @@
<el-form-item label="收费情况" prop="charge">
<el-input v-model="formData.charge" placeholder="请输入" />
</el-form-item>
<el-form-item label="合同" prop="AcademicResume">
<el-form-item label="描述" prop="description">
<el-input
v-model="formData.description"
type="textarea"
placeholder="描述"
:rows="4"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="合同" prop="contract">
<el-upload
class="avatar-uploader"
action="#"
:auto-upload="false"
:show-file-list="false"
:on-change="(file) => handleFileSelect(file, 'AcademicResume')"
:on-change="(file) => handleFileSelect(file, 'contract')"
:before-upload="handleBeforeUpload"
>
<div v-if="formData.AcademicResume" class="upload-preview">
<span>{{ formData.AcademicResume.name }}</span>
<el-button type="danger" size="small" @click.stop="removeFile('AcademicResume')">
<div v-if="formData.contract" class="upload-preview">
<span>{{ formData.contract.name }}</span>
<el-button type="danger" size="small" @click.stop="removeFile('contract')">
删除
</el-button>
</div>
@@ -188,9 +94,20 @@
</template>
<script lang="ts" setup>
import { Delete, Plus } from '@element-plus/icons-vue'
import { UserPersonneldisplay } from '@/api/calibration/personnelManagement'
import { ElMessage } from 'element-plus'
import { BusinessProjectquerytype } from '@/api/calibration/conflictOfInterestSearch'
import { BusinessRegistrationlist } from '@/api/calibration/preRegistration'
const typeList = [
{ name: '法律顾问', value: '顾' },
{ name: '专项服务', value: '专' },
{ name: '民事案件代理', value: '代' },
{ name: '刑事案件代理', value: '刑辩' },
{ name: '行政案件代理', value: '行政' },
{ name: '法律咨询', value: '询' },
{ name: '破产程序代理', value: '破产' }
]
const formRef = ref()
// 表单数据
@@ -198,124 +115,28 @@ const formData = reactive<any>({
type: '',
ContractNo: '',
times: '',
client_info: [{ index: 1, name: '', idNumber: '' }],
party_info: [{ index: 1, name: '', idNumber: '' }],
description: '',
responsiblefor: '',
charge: '',
contract: undefined
contract: undefined,
personincharge: '',
user_id: ''
})
const UndertakerList = ref<any[]>([])
// 选择的委托人
const selectedClients = ref<any[]>([])
// 选择的相对方
const selectedOpponents = ref<any[]>([])
const userIdList = ref<any[]>([])
const formRules = reactive<any>({
type: [{ required: true, message: '请选择预立案日期', trigger: 'change' }],
ContractNo: [{ required: true, message: '请输入', trigger: 'change' }],
times: [{ required: true, message: '请选择预立案日期', trigger: 'change' }],
description: [{ required: true, message: '请填写项目简述/案由', trigger: 'blur' }],
responsiblefor: [{ required: true, message: '请选择承办人员', trigger: 'change' }],
clientName: [{ required: true, message: '请输入姓名/法人名称', trigger: 'blur' }],
clientIdNumber: [{ required: true, message: '请输入身份证号码/统一代码', trigger: 'blur' }],
opponentName: [{ required: true, message: '请输入姓名/法人名称', trigger: 'blur' }],
opponentIdNumber: [{ required: true, message: '请输入身份证号码/统一代码', trigger: 'blur' }]
responsiblefor: [{ required: true, message: '请选择负责人', trigger: 'change' }],
charge: [{ required: true, message: '请输入', trigger: 'blur' }],
contract: [{ required: true, message: '请选择合同', trigger: 'blur' }],
personincharge: [{ required: true, message: '请选择审核人', trigger: 'blur' }],
user_id: [{ required: true, message: '请选择预立案', trigger: 'blur' }]
})
// 处理委托人选择
const handleClientSelectionChange = (selection: any[]) => {
selectedClients.value = selection
}
// 处理相对方选择
const handleOpponentSelectionChange = (selection: any[]) => {
selectedOpponents.value = selection
}
// 新增委托人
const addClient = () => {
const newIndex = formData.client_info.length + 1
formData.client_info.push({ index: newIndex, name: '', idNumber: '' })
}
// 删除委托人
const deleteClient = (index: number) => {
if (formData.client_info.length > 1) {
formData.client_info.splice(index, 1)
// 更新序号
formData.client_info.forEach((client: any, idx: number) => {
client.index = idx + 1
})
} else if (formData.party_info.length === 0) {
ElMessage.warning('委托方和相对方至少需要存在一个')
} else {
formData.client_info.splice(index, 1)
}
}
// 复制委托人
const copyClient = (client: any) => {
const newIndex = formData.client_info.length + 1
formData.client_info.push({ ...client, index: newIndex })
}
// 批量删除委托人
const batchDeleteClients = () => {
if (selectedClients.value.length === 0) {
ElMessage.warning('请选择要删除的委托人')
return
}
// 检查是否删除后还剩至少一个(或相对方存在)
if (
formData.client_info.length - selectedClients.value.length === 0 &&
formData.party_info.length === 0
) {
ElMessage.warning('委托方和相对方至少需要存在一个')
return
}
// 执行批量删除
formData.client_info = formData.client_info.filter(
(client: any) => !selectedClients.value.includes(client)
)
// 更新序号
formData.client_info.forEach((client: any, idx: number) => {
client.index = idx + 1
})
// 清空选择
selectedClients.value = []
ElMessage.success('批量删除成功')
}
// 新增相对方
const addOpponent = () => {
const newIndex = formData.party_info.length + 1
formData.party_info.push({ index: newIndex, name: '', idNumber: '' })
}
// 删除相对方
const deleteOpponent = (index: number) => {
if (formData.party_info.length > 1) {
formData.party_info.splice(index, 1)
// 更新序号
formData.party_info.forEach((opponent: any, idx: number) => {
opponent.index = idx + 1
})
} else if (formData.client_info.length === 0) {
ElMessage.warning('委托方和相对方至少需要存在一个')
} else {
formData.party_info.splice(index, 1)
}
}
// 复制相对方
const copyOpponent = (opponent: any) => {
const newIndex = formData.party_info.length + 1
formData.party_info.push({ ...opponent, index: newIndex })
}
function handleFileSelect(file: any, field: string): void {
// 将文件对象保存到表单数据中
formData[field] = file.raw // file.raw 是实际的 File 对象
@@ -345,7 +166,29 @@ const DepartmentList = () => {
})
}
const typeChange = async (value: string) => {
const parts = value.split(',')
if (parts.length < 2) {
console.error('Invalid value format')
return
}
formData.ContractNo = await generateContractNo(parts)
}
const generateContractNo = async (typeValue: any[]) => {
const currentYear = new Date().getFullYear()
const counter = await BusinessProjectquerytype(typeValue[0])
return `校准(${typeValue[1]})字【${currentYear}】第${counter.data.count + 1}号`
}
const onBusinessRegistrationlist = () => {
BusinessRegistrationlist().then((res: any) => {
userIdList.value = res.data
})
}
onMounted(() => {
onBusinessRegistrationlist()
DepartmentList()
})
@@ -357,12 +200,6 @@ const submit = (): Promise<boolean> => {
return new Promise((resolve, reject) => {
formRef.value?.validate((valid: boolean) => {
if (valid) {
// 验证委托方和相对方至少存在一个
if (formData.client_info.length === 0 || formData.party_info.length === 0) {
ElMessage.error('委托方和相对方至少需要存在一个')
reject(false)
return
}
resolve(true)
} else {
ElMessage.error('请完善必填信息')

View File

@@ -4,74 +4,71 @@
<!-- 搜索区域 -->
<div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto">
<el-form-item label="委托人信息" prop="keywords">
<el-form-item label="委托人信息" prop="client_username">
<el-input
v-model="queryParams.keywords"
v-model="searchs.client_username"
placeholder="自然人姓名/身份证号码/法人机构名称/统一社会信用代码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="相对方信息" prop="keywords">
<el-form-item label="相对方信息" prop="party_username">
<el-input
v-model="queryParams.keywords"
v-model="searchs.party_username"
placeholder="自然人姓名/身份证号码/法人机构名称/统一社会信用代码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item class="search-buttons">
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="refresh" @click="handleResetQuery">重置</el-button>
<el-button type="primary" icon="search" @click="handleQuery()">搜索</el-button>
<el-button icon="refresh" @click="handleResetQuery()">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-button
type="primary"
icon="edit"
style="margin-bottom: 20px"
@click="handleOpenDialog('立项登记')"
>
<el-button type="primary" icon="Plus" style="margin-bottom: 20px" @click="handleOpenDialog()">
立项登记
</el-button>
<el-button
type="success"
icon="Plus"
style="margin-bottom: 20px"
@click="handleOpenDialog('投标登记')"
>
投标登记
</el-button>
<el-card shadow="hover" class="data-table">
<el-table
v-loading="loading"
:data="pageData"
:data="projectRegistrationData"
border
stripe
max-height="280"
highlight-current-row
class="data-table__content"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column label="案件名" prop="username" />
<el-table-column label="委托人姓名" width="150" align="center" prop="nickname" />
<el-table-column label="委托人身份证" width="120" align="center" prop="deptName" />
<el-table-column label="相对方姓名" width="150" align="center" prop="mobile" />
<el-table-column label="相对方身份证" align="center" prop="email" width="160" />
<el-table-column label="主办律师" align="center" prop="createTime" width="150" />
<el-table-column label="协办律师" align="center" prop="createTime" width="150" />
<el-table-column label="律师助理" align="center" prop="createTime" width="150" />
<el-table-column label="预立案" prop="user_id" />
<el-table-column label="项目类型" align="center" prop="type" />
<el-table-column label="合同编号" align="center" prop="ContractNo" />
<el-table-column label="负责人" align="center" prop="responsiblefor" />
<el-table-column label="收费情况" align="center" prop="charge" />
<el-table-column label="合同" align="center" prop="contract">
<template #default="{ row }">
<el-link
v-if="row.contract && isValidJson(row.contract)"
:href="getFileInfo(row.contract)?.url"
target="_blank"
>
{{ getFileInfo(row.contract)?.name }}
</el-link>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="立项日期时间" align="center" prop="times" />
<el-table-column label="操作" align="center" width="220">
<template #default="scope">
<el-button
v-hasPerm="'sys:user:reset-password'"
type="primary"
icon="RefreshLeft"
icon="edit"
size="small"
link
@click="handleResetPassword(scope.row)"
>
重置密码
编辑
</el-button>
</template>
</el-table-column>
@@ -84,131 +81,87 @@
@pagination="fetchUserList"
/>
</el-card>
<!-- 用户表单 -->
<el-drawer
v-model="dialog.visible"
:title="dialog.title"
append-to-body
:size="drawerSize"
@close="handleCloseDialog"
>
<el-form
v-show="dialog.title === '立项登记'"
ref="userFormRef"
:model="formData"
:rules="rules"
label-width="80px"
<el-button type="primary" icon="Plus" style="margin-bottom: 20px" @click="handleOpenDialog2()">
投标登记
</el-button>
<el-card shadow="hover" class="data-table">
<el-table
v-loading="loading"
:data="bidRegistrationData"
border
stripe
max-height="280"
highlight-current-row
class="data-table__content"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-form-item label="用户名" prop="username">
<el-input
v-model="formData.username"
:readonly="!!formData.id"
placeholder="请输入用户名"
/>
</el-form-item>
<el-form-item label="用户昵称" prop="nickname">
<el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
</el-form-item>
<el-form-item label="所属部门" prop="deptId">
<el-tree-select
v-model="formData.deptId"
placeholder="请选择所属部门"
:data="deptOptions"
filterable
check-strictly
:render-after-expand="false"
/>
</el-form-item>
<el-form-item label="性别" prop="gender">
<Dict v-model="formData.gender" code="gender" />
</el-form-item>
<el-form-item label="角色" prop="roleIds">
<el-select v-model="formData.roleIds" multiple placeholder="请选择">
<el-option
v-for="item in roleOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="手机号码" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-switch
v-model="formData.status"
inline-prompt
active-text="正常"
inactive-text="禁用"
:active-value="1"
:inactive-value="0"
/>
</el-form-item>
</el-form>
<el-form
v-show="dialog.title === '投标登记'"
ref="userFormRef"
:model="formDataTender"
:rules="rulesTender"
label-width="80px"
>
<el-form-item label="案件名" prop="username">
<el-input
v-model="formData.username"
:readonly="!!formData.id"
placeholder="请输入案件名"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSubmit"> </el-button>
<el-button @click="handleCloseDialog"> </el-button>
</div>
</template>
</el-drawer>
<el-table-column label="预立案" prop="user_id" />
<el-table-column label="招标单位信息" align="center" prop="BiddingUnit">
<el-table-column v-slot="{ row }" prop="BiddingUnit" label="自然人姓名/法人名称">
{{
JSON.parse(row.BiddingUnit)
.map((item: any) => item.name)
.join('')
}}
</el-table-column>
<el-table-column v-slot="{ row }" prop="BiddingUnit" label="身份证号码/统一代码">
{{
JSON.parse(row.BiddingUnit)
.map((item: any) => item.idNumber)
.join('')
}}
</el-table-column>
</el-table-column>
<el-table-column label="项目名称" align="center" prop="ProjectName" />
<el-table-column label="上传招标公告" align="center" prop="BiddingAnnouncement" />
<el-table-column label="申请日期" align="center" prop="times" />
<el-table-column label="操作" align="center" width="220">
<template #default="scope">
<el-button
type="primary"
icon="edit"
size="small"
link
@click="handleResetPassword(scope.row)"
>
编辑
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-if="total2 > 0"
v-model:total="total2"
v-model:page="queryParams2.pageNum"
v-model:limit="queryParams2.pageSize"
@pagination="fetchUserList2"
/>
</el-card>
</div>
</template>
<script setup lang="ts">
// ==================== 1. Vue 核心 API ====================
import { computed, onMounted, reactive, ref } from 'vue'
import { onMounted, reactive, ref } from 'vue'
import { useDebounceFn } from '@vueuse/core'
// ==================== 2. Element Plus ====================
import { ElMessage, ElMessageBox } from 'element-plus'
// ==================== 3. 类型定义 ====================
import type { UserForm, UserPageQuery, UserPageVO } from '@/api/system/user-api'
import type { UserPageVO } from '@/api/system/user-api'
// ==================== 4. API 服务 ====================
import UserAPI from '@/api/system/user-api'
// ==================== 5. Store ====================
import { useAppStore } from '@/store/modules/app-store'
// import { useUserStore } from '@/store';
// ==================== 6. Enums ====================
import { DeviceEnum } from '@/enums/settings/device-enum'
// ==================== 7. Composables ====================
import { useAiAction, useTableSelection } from '@/composables'
import { useTableSelection } from '@/composables'
import { functionDialogBox } from '@/utils/functionDialogBox'
import BusinessProjectForm from './components/BusinessProjectForm.vue'
// ==================== 8. 组件 ====================
// import DeptTree from './components/DeptTree.vue';
// import UserImport from './components/UserImport.vue';
import { BusinessProject, BusinessProjectdetail } from '@/api/calibration/conflictOfInterestSearch'
import BidRegistrationForm from './components/BidRegistrationForm.vue'
import { BusinessBid, BusinessBiddetail } from '@/api/calibration/bidRegistration'
import { getFileInfo, isValidJson } from '@/utils/auxiliaryFunction'
// ==================== 组件配置 ====================
defineOptions({
@@ -216,114 +169,31 @@ defineOptions({
inheritAttrs: false
})
// ==================== Store 实例 ====================
const appStore = useAppStore()
// const userStore = useUserStore();
// ==================== 响应式状态 ====================
// DOM 引用
const queryFormRef = ref()
const userFormRef = ref()
// 列表查询参数
const queryParams = reactive<UserPageQuery>({
const queryParams = reactive<any>({
pageNum: 1,
pageSize: 10
})
const queryParams2 = reactive<any>({
pageNum: 1,
pageSize: 10
})
const searchs = reactive<any>({
times: [],
client_username: '',
party_username: ''
})
// 列表数据
const pageData = ref<UserPageVO[]>()
const projectRegistrationData = ref<any[]>([])
const bidRegistrationData = ref<any[]>([])
const total = ref(0)
const total2 = ref(0)
const loading = ref(false)
// 弹窗状态
const dialog = reactive({
visible: false,
title: '新增用户'
})
// 表单数据
const formData = reactive<UserForm>({
status: 1
})
// 登记表格数据
const formDataTender = reactive<UserForm>({
status: 1
})
// 下拉选项数据
const deptOptions = ref<OptionType[]>()
const roleOptions = ref<OptionType[]>()
// 导入弹窗
// const importDialogVisible = ref(false);
// ==================== 计算属性 ====================
/**
* 抽屉尺寸(响应式)
*/
const drawerSize = computed(() => (appStore.device === DeviceEnum.DESKTOP ? '600px' : '90%'))
// ==================== 表单验证规则 ====================
const rules = reactive({
username: [
{
required: true,
message: '用户名不能为空',
trigger: 'blur'
}
],
nickname: [
{
required: true,
message: '用户昵称不能为空',
trigger: 'blur'
}
],
deptId: [
{
required: true,
message: '所属部门不能为空',
trigger: 'blur'
}
],
roleIds: [
{
required: true,
message: '用户角色不能为空',
trigger: 'blur'
}
],
email: [
{
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
message: '请输入正确的邮箱地址',
trigger: 'blur'
}
],
mobile: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
]
})
const rulesTender = reactive({
username: [
{
required: true,
message: '案件名不能为空',
trigger: 'blur'
}
]
})
// ==================== 数据加载 ====================
/**
@@ -332,9 +202,22 @@ const rulesTender = reactive({
async function fetchUserList(): Promise<void> {
loading.value = true
try {
const data = await UserAPI.getPage(queryParams)
pageData.value = data.list
total.value = data.total
const res: any = await BusinessProjectdetail({ ...queryParams, ...searchs })
projectRegistrationData.value = res.data
total.value = res.total
} catch (error) {
ElMessage.error('获取用户列表失败')
console.error('获取用户列表失败:', error)
} finally {
loading.value = false
}
}
async function fetchUserList2(): Promise<void> {
loading.value = true
try {
const res: any = await BusinessBiddetail({ ...queryParams2, ...searchs })
bidRegistrationData.value = res.data
total2.value = res.total
} catch (error) {
ElMessage.error('获取用户列表失败')
console.error('获取用户列表失败:', error)
@@ -342,7 +225,6 @@ async function fetchUserList(): Promise<void> {
loading.value = false
}
}
// ==================== 表格选择 ====================
const { handleSelectionChange } = useTableSelection<UserPageVO>()
@@ -351,19 +233,22 @@ const { handleSelectionChange } = useTableSelection<UserPageVO>()
/**
* 查询用户列表
*/
function handleQuery(): Promise<void> {
function handleQuery(biaoshi: string = '1'): Promise<void> {
queryParams.pageNum = 1
return fetchUserList()
queryParams2.pageNum = 1
if (biaoshi == '1' || biaoshi == '2') fetchUserList2()
if (biaoshi == '1' || biaoshi == '3') fetchUserList()
return Promise.resolve()
}
/**
* 重置查询条件
*/
function handleResetQuery(): void {
function handleResetQuery(biaoshi: string = '1'): void {
queryFormRef.value.resetFields()
queryParams.deptId = undefined
queryParams.createTime = undefined
handleQuery()
handleQuery(biaoshi)
}
// ==================== 用户操作 ====================
@@ -390,14 +275,8 @@ function handleResetPassword(row: UserPageVO): void {
}
})
}
// ==================== 弹窗操作 ====================
/**
* 打开用户表单弹窗
* @param id 用户ID编辑时传入
*/
async function handleOpenDialog(titleString: string, id?: string): Promise<void> {
async function handleOpenDialog(): Promise<void> {
// dialog.visible = true
// dialog.title = titleString
//
@@ -426,105 +305,98 @@ async function handleOpenDialog(titleString: string, id?: string): Promise<void>
BusinessProjectForm,
{},
{
title: '新增立案登记',
title: '新增立案登记',
width: '900',
ok(value: any) {
console.log('value', value)
handleSubmit(value)
}
// cancel() {
// console.log("value");
// },
}
)
}
/**
* 关闭用户表单弹窗
*/
function handleCloseDialog(): void {
dialog.visible = false
userFormRef.value.resetFields()
userFormRef.value.clearValidate()
// 重置表单数据
formData.id = undefined
formData.status = 1
async function handleOpenDialog2(): Promise<void> {
// dialog.visible = true
// dialog.title = titleString
//
// // 并行加载下拉选项数据
// try {
// ;[roleOptions.value, deptOptions.value] = await Promise.all([
// RoleAPI.getOptions(),
// DeptAPI.getOptions()
// ])
// } catch (error) {
// ElMessage.error('加载选项数据失败')
// console.error('加载选项数据失败:', error)
// }
//
// // 编辑:加载用户数据
// if (id) {
// try {
// const data = await UserAPI.getFormData(id)
// Object.assign(formData, data)
// } catch (error) {
// ElMessage.error('加载用户数据失败')
// console.error('加载用户数据失败:', error)
// }
// }
functionDialogBox(
BidRegistrationForm,
{},
{
title: '新增投标登记',
width: '900',
ok(value: any) {
handleSubmit2(value)
}
}
)
}
/**
* 提交用户表单(防抖)
*/
const handleSubmit = useDebounceFn(async (data: any) => {
const valid = await userFormRef.value.validate().catch(() => false)
if (!valid) return
const userId = data.id
loading.value = true
try {
if (userId) {
await UserAPI.update(userId, formData)
// await UserAPI.update(userId, formData)
ElMessage.success('修改用户成功')
} else {
// await UserAPI.create(data)
console.log(data)
await BusinessProject(data)
ElMessage.success('新增用户成功')
}
handleCloseDialog()
handleResetQuery()
handleResetQuery('2')
} catch (error) {
ElMessage.error(userId ? '修改用户失败' : '新增用户失败')
console.error('提交用户表单失败:', error)
} finally {
loading.value = false
}
}, 1000)
}, 300)
const handleSubmit2 = useDebounceFn(async (data: any) => {
const userId = data.id
loading.value = true
// ==================== AI 助手相关 ====================
useAiAction({
actionHandlers: {
/**
* AI 修改用户昵称
* 使用配置对象方式:自动处理确认、执行、反馈
*/
updateUserNickname: {
needConfirm: true,
callBackendApi: true, // 自动调用后端 API
confirmMessage: (args: any) =>
`AI 助手将执行以下操作:<br/>
<strong>修改用户:</strong> ${args.username}<br/>
<strong>新昵称:</strong> ${args.nickname}<br/><br/>
确认执行吗?`,
successMessage: (args: any) => `已将用户 ${args.username} 的昵称修改为 ${args.nickname}`,
execute: async () => {
// callBackendApi=true 时execute 可以为空
// Composable 会自动调用后端 API
}
},
/**
* AI 查询用户
* 使用配置对象方式:查询操作不需要确认
*/
queryUser: {
needConfirm: false, // 查询操作无需确认
successMessage: (args: any) => `已搜索:${args.keywords}`,
execute: async (args: any) => {
queryParams.keywords = args.keywords
await handleQuery()
}
try {
if (userId) {
// await UserAPI.update(userId, formData)
ElMessage.success('修改用户成功')
} else {
await BusinessBid({
...data,
BiddingUnit: JSON.stringify(data.BiddingUnit)
})
ElMessage.success('新增用户成功')
}
},
onRefresh: fetchUserList,
onAutoSearch: (keywords: string) => {
queryParams.keywords = keywords
setTimeout(() => {
handleQuery()
ElMessage.success(`AI 助手已为您自动搜索:${keywords}`)
}, 300)
handleResetQuery('3')
} catch (error) {
ElMessage.error(userId ? '修改用户失败' : '新增用户失败')
console.error('提交用户表单失败:', error)
} finally {
loading.value = false
}
})
}, 300)
// ==================== 生命周期 ====================

View File

@@ -218,7 +218,6 @@ function handleOpenDialog(roleId?: string) {
title: '新增预立案登记',
width: '900',
ok(value: any) {
console.log('value', value)
handleSubmit(value)
}
// cancel() {