对接预立案登记接口、对接立项登记接口

This commit is contained in:
雷校云
2025-12-15 18:43:45 +08:00
parent d57f6838a3
commit 81fd3b2144
8 changed files with 1882 additions and 162 deletions

View File

@@ -0,0 +1,43 @@
import request from '@/utils/request'
const AUTH_BASE_URL = '/api2'
/*
* 立项登记
* */
// 新增立项登记
export const BusinessProject = (data: any) => {
const formData = new FormData()
formData.append('type', data.type)
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)
return request({
url: `${AUTH_BASE_URL}/business/project`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 审批分页接口
export const UserRoxyexhibition = (data: any) => {
const formData = new FormData()
formData.append('page', data.pageNum)
formData.append('per_page', data.pageSize)
return request({
url: `${AUTH_BASE_URL}/user/roxyexhibition`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}

View File

@@ -0,0 +1,46 @@
import request from '@/utils/request'
const AUTH_BASE_URL = '/api2'
/*
* 预立案登记
* */
// 新增预立案登记
export const BusinessRegister = (data: any) => {
const formData = new FormData()
formData.append('times', data.times)
formData.append('client_username', data.client_username)
formData.append('client_card', data.client_card)
formData.append('party_username', data.party_username)
formData.append('party_card', data.party_card)
formData.append('description', data.description)
formData.append('Undertaker', data.Undertaker)
return request({
url: `${AUTH_BASE_URL}/business/register`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 审批分页接口
export const BusinessRegisterdetail = (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])
}
if (data.Undertaker) formData.append('Undertaker', data.Undertaker)
return request({
url: `${AUTH_BASE_URL}/business/registerdetail`,
method: 'post',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}

View File

@@ -175,17 +175,20 @@ export const constantRoutes: RouteRecordRaw[] = [
},
children: [
{
path: 'user',
name: 'BusinessConflict',
component: () => import('@/views/business/conflict/index.vue'),
path: 'conflictOfInterestSearch',
name: 'ConflictOfInterestSearch',
component: () =>
import('@/views/calibration/businessSystem/conflictOfInterestSearch/index.vue'),
// component: () => import('@/views/business/conflict/index.vue'),
meta: {
title: '利益冲突检索'
}
},
{
path: 'role',
name: 'BusinessPreRegistration',
component: () => import('@/views/business/preRegistration/index.vue'),
path: 'preRegistration',
name: 'PreRegistration',
// component: () => import('@/views/business/preRegistration/index.vue'),
component: () => import('@/views/calibration/businessSystem/preRegistration/index.vue'),
meta: {
title: '预立案登记'
}

View File

@@ -0,0 +1,409 @@
<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="type">
<el-select v-model="formData.type" placeholder="请选择项目类型">
<el-option
v-for="item in UndertakerList"
:key="item.id"
:label="item.username"
:value="item.username"
/>
</el-select>
</el-form-item>
<el-form-item label="合同编号" prop="ContractNo">
<el-input v-model="formData.ContractNo" disabled 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="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
v-for="item in UndertakerList"
:key="item.id"
:label="item.username"
:value="item.username"
/>
</el-select>
</el-form-item>
<el-form-item label="收费情况" prop="charge">
<el-input v-model="formData.charge" placeholder="请输入" />
</el-form-item>
<el-form-item label="合同" prop="AcademicResume">
<el-upload
class="avatar-uploader"
action="#"
:auto-upload="false"
:show-file-list="false"
:on-change="(file) => handleFileSelect(file, 'AcademicResume')"
: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')">
删除
</el-button>
</div>
<el-button v-else size="small" type="primary">点击选择文件</el-button>
</el-upload>
</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 { Delete, Plus } from '@element-plus/icons-vue'
import { UserPersonneldisplay } from '@/api/calibration/personnelManagement'
import { ElMessage } from 'element-plus'
const formRef = ref()
// 表单数据
const formData = reactive<any>({
type: '',
ContractNo: '',
times: '',
client_info: [{ index: 1, name: '', idNumber: '' }],
party_info: [{ index: 1, name: '', idNumber: '' }],
description: '',
responsiblefor: '',
charge: '',
contract: undefined
})
const UndertakerList = ref<any[]>([])
// 选择的委托人
const selectedClients = ref<any[]>([])
// 选择的相对方
const selectedOpponents = ref<any[]>([])
const formRules = reactive<any>({
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' }]
})
// 处理委托人选择
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 对象
console.log(formData[field])
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
})
}
onMounted(() => {
DepartmentList()
})
const getForm = () => {
return formData
}
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('请完善必填信息')
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;
}
</style>

View File

@@ -0,0 +1,540 @@
<!-- 用户管理 -->
<template>
<div class="app-container">
<!-- 搜索区域 -->
<div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="auto">
<el-form-item label="委托人信息" prop="keywords">
<el-input
v-model="queryParams.keywords"
placeholder="自然人姓名/身份证号码/法人机构名称/统一社会信用代码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="相对方信息" prop="keywords">
<el-input
v-model="queryParams.keywords"
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-form-item>
</el-form>
</div>
<el-button
type="primary"
icon="edit"
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"
border
stripe
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="操作" align="center" width="220">
<template #default="scope">
<el-button
v-hasPerm="'sys:user:reset-password'"
type="primary"
icon="RefreshLeft"
size="small"
link
@click="handleResetPassword(scope.row)"
>
重置密码
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-if="total > 0"
v-model:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@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-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>
</div>
</template>
<script setup lang="ts">
// ==================== 1. Vue 核心 API ====================
import { computed, 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'
// ==================== 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 { functionDialogBox } from '@/utils/functionDialogBox'
import BusinessProjectForm from './components/BusinessProjectForm.vue'
// ==================== 8. 组件 ====================
// import DeptTree from './components/DeptTree.vue';
// import UserImport from './components/UserImport.vue';
// ==================== 组件配置 ====================
defineOptions({
name: 'SystemUser',
inheritAttrs: false
})
// ==================== Store 实例 ====================
const appStore = useAppStore()
// const userStore = useUserStore();
// ==================== 响应式状态 ====================
// DOM 引用
const queryFormRef = ref()
const userFormRef = ref()
// 列表查询参数
const queryParams = reactive<UserPageQuery>({
pageNum: 1,
pageSize: 10
})
// 列表数据
const pageData = ref<UserPageVO[]>()
const total = 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'
}
]
})
// ==================== 数据加载 ====================
/**
* 获取用户列表数据
*/
async function fetchUserList(): Promise<void> {
loading.value = true
try {
const data = await UserAPI.getPage(queryParams)
pageData.value = data.list
total.value = data.total
} catch (error) {
ElMessage.error('获取用户列表失败')
console.error('获取用户列表失败:', error)
} finally {
loading.value = false
}
}
// ==================== 表格选择 ====================
const { handleSelectionChange } = useTableSelection<UserPageVO>()
// ==================== 查询操作 ====================
/**
* 查询用户列表
*/
function handleQuery(): Promise<void> {
queryParams.pageNum = 1
return fetchUserList()
}
/**
* 重置查询条件
*/
function handleResetQuery(): void {
queryFormRef.value.resetFields()
queryParams.deptId = undefined
queryParams.createTime = undefined
handleQuery()
}
// ==================== 用户操作 ====================
/**
* 重置用户密码
* @param row 用户数据
*/
function handleResetPassword(row: UserPageVO): void {
ElMessageBox.prompt(`请输入用户【${row.username}】的新密码`, '重置密码', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: /.{6,}/,
inputErrorMessage: '密码至少需要6位字符'
})
.then(({ value }) => {
return UserAPI.resetPassword(row.id, value)
})
.then(() => {
ElMessage.success('密码重置成功')
})
.catch((error) => {
if (error !== 'cancel') {
ElMessage.error('密码重置失败')
}
})
}
// ==================== 弹窗操作 ====================
/**
* 打开用户表单弹窗
* @param id 用户ID编辑时传入
*/
async function handleOpenDialog(titleString: string, id?: string): 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(
BusinessProjectForm,
{},
{
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
}
/**
* 提交用户表单(防抖)
*/
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)
ElMessage.success('修改用户成功')
} else {
// await UserAPI.create(data)
console.log(data)
ElMessage.success('新增用户成功')
}
handleCloseDialog()
handleResetQuery()
} catch (error) {
ElMessage.error(userId ? '修改用户失败' : '新增用户失败')
console.error('提交用户表单失败:', error)
} finally {
loading.value = false
}
}, 1000)
// ==================== 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()
}
}
},
onRefresh: fetchUserList,
onAutoSearch: (keywords: string) => {
queryParams.keywords = keywords
setTimeout(() => {
handleQuery()
ElMessage.success(`AI 助手已为您自动搜索:${keywords}`)
}, 300)
}
})
// ==================== 生命周期 ====================
/**
* 组件挂载时初始化数据
*
* 注意:这里会先加载列表数据,如果 URL 中有 AI 参数(如搜索关键字),
* useAiAction 会在 nextTick 中再次执行搜索,这是预期行为
*/
onMounted(() => {
handleQuery()
})
</script>

View File

@@ -0,0 +1,359 @@
<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="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="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_username"
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_username.' + 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_username.' + 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_username"
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_username.' + 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_username.' + 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="Undertaker">
<el-select v-model="formData.Undertaker" 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 { Delete, Plus } from '@element-plus/icons-vue'
import { UserPersonneldisplay } from '@/api/calibration/personnelManagement'
const formRef = ref()
// 表单数据
const formData = reactive<any>({
times: '',
client_username: [{ index: 1, name: '', idNumber: '' }],
party_username: [{ index: 1, name: '', idNumber: '' }],
description: '',
Undertaker: ''
})
const UndertakerList = ref<any[]>([])
// 选择的委托人
const selectedClients = ref<any[]>([])
// 选择的相对方
const selectedOpponents = ref<any[]>([])
const formRules = reactive<any>({
times: [{ required: true, message: '请选择预立案日期', trigger: 'change' }],
description: [{ required: true, message: '请填写项目简述/案由', trigger: 'blur' }],
Undertaker: [{ 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' }]
})
// 处理委托人选择
const handleClientSelectionChange = (selection: any[]) => {
selectedClients.value = selection
}
// 处理相对方选择
const handleOpponentSelectionChange = (selection: any[]) => {
selectedOpponents.value = selection
}
// 新增委托人
const addClient = () => {
const newIndex = formData.client_username.length + 1
formData.client_username.push({ index: newIndex, name: '', idNumber: '' })
}
// 删除委托人
const deleteClient = (index: number) => {
if (formData.client_username.length > 1) {
formData.client_username.splice(index, 1)
// 更新序号
formData.client_username.forEach((client: any, idx: number) => {
client.index = idx + 1
})
} else if (formData.party_username.length === 0) {
ElMessage.warning('委托方和相对方至少需要存在一个')
} else {
formData.client_username.splice(index, 1)
}
}
// 复制委托人
const copyClient = (client: any) => {
const newIndex = formData.client_username.length + 1
formData.client_username.push({ ...client, index: newIndex })
}
// 批量删除委托人
const batchDeleteClients = () => {
if (selectedClients.value.length === 0) {
ElMessage.warning('请选择要删除的委托人')
return
}
// 检查是否删除后还剩至少一个(或相对方存在)
if (
formData.client_username.length - selectedClients.value.length === 0 &&
formData.party_username.length === 0
) {
ElMessage.warning('委托方和相对方至少需要存在一个')
return
}
// 执行批量删除
formData.client_username = formData.client_username.filter(
(client: any) => !selectedClients.value.includes(client)
)
// 更新序号
formData.client_username.forEach((client: any, idx: number) => {
client.index = idx + 1
})
// 清空选择
selectedClients.value = []
ElMessage.success('批量删除成功')
}
// 新增相对方
const addOpponent = () => {
const newIndex = formData.party_username.length + 1
formData.party_username.push({ index: newIndex, name: '', idNumber: '' })
}
// 删除相对方
const deleteOpponent = (index: number) => {
if (formData.party_username.length > 1) {
formData.party_username.splice(index, 1)
// 更新序号
formData.party_username.forEach((opponent: any, idx: number) => {
opponent.index = idx + 1
})
} else if (formData.client_username.length === 0) {
ElMessage.warning('委托方和相对方至少需要存在一个')
} else {
formData.party_username.splice(index, 1)
}
}
// 复制相对方
const copyOpponent = (opponent: any) => {
const newIndex = formData.party_username.length + 1
formData.party_username.push({ ...opponent, index: newIndex })
}
// 暂存表单
// const handleSaveDraft = () => {
// // 保存草稿逻辑
// console.log('暂存表单数据:', formData)
// ElMessage.success('表单暂存成功')
// }
const DepartmentList = () => {
UserPersonneldisplay().then((res: any) => {
UndertakerList.value = res.data
})
}
onMounted(() => {
DepartmentList()
})
const getForm = () => {
return formData
}
const submit = (): Promise<boolean> => {
return new Promise((resolve, reject) => {
formRef.value?.validate((valid: boolean) => {
if (valid) {
// 验证委托方和相对方至少存在一个
if (formData.client_username.length === 0 || formData.party_username.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;
}
</style>

View File

@@ -0,0 +1,320 @@
<template>
<div class="app-container">
<!-- 搜索区域 -->
<div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item prop="person" label="报销人">
<el-input
v-model="queryParams.person"
placeholder="请输入报销人"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间" prop="times">
<el-date-picker
v-model="queryParams.times"
type="daterange"
value-format="YYYY-MM-DD"
placeholder="请选择创建时间"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</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-form-item>
</el-form>
</div>
<el-card shadow="hover" class="data-table">
<div class="data-table__toolbar">
<div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog()">新增</el-button>
<el-button
type="danger"
:disabled="ids.length === 0"
icon="delete"
@click="handleDelete()"
>
删除
</el-button>
</div>
</div>
<el-table
ref="dataTableRef"
v-loading="loading"
:data="roleList"
highlight-current-row
border
class="data-table__content"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="委托人信息" prop="client_username">
<el-table-column v-slot="{ row }" prop="client_username" label="自然人姓名/法人名称">
{{
JSON.parse(row.client_username)
.map((item: any) => item.name)
.join('')
}}
</el-table-column>
<el-table-column v-slot="{ row }" prop="client_username" label="身份证号码/统一代码">
{{
JSON.parse(row.client_username)
.map((item: any) => item.idNumber)
.join('')
}}
</el-table-column>
</el-table-column>
<el-table-column label="相对方信息" prop="party_username">
<el-table-column v-slot="{ row }" prop="party_username" label="自然人姓名/法人名称">
{{
JSON.parse(row.party_username)
.map((item: any) => item.name)
.join('')
}}
</el-table-column>
<el-table-column v-slot="{ row }" prop="party_username" label="身份证号码/统一代码">
{{
JSON.parse(row.party_username)
.map((item: any) => item.idNumber)
.join('')
}}
</el-table-column>
</el-table-column>
<el-table-column label="承办人员" prop="Undertaker" />
<el-table-column label="描述" prop="description" />
<el-table-column label="时间" prop="times" />
<el-table-column fixed="right" label="操作" width="220">
<template #default="scope">
<el-button
type="primary"
size="small"
link
icon="edit"
@click="handleOpenDialog(scope.row.id)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
link
icon="delete"
@click="onUserDeleteDepartment(scope.row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-if="total > 0"
v-model:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="fetchData"
/>
</el-card>
</div>
</template>
<script setup lang="ts">
import RoleAPI, { RolePageVO } from '@/api/system/role-api'
import { UserDeleteDepartment } from '@/api/calibration/department'
import { UserPersonneldisplay } from '@/api/calibration/personnelManagement'
import { functionDialogBox } from '@/utils/functionDialogBox'
import PreRegistrationForm from './components/PreRegistrationForm.vue'
import { BusinessRegister, BusinessRegisterdetail } from '@/api/calibration/preRegistration'
defineOptions({
name: 'Role',
inheritAttrs: false
})
const queryFormRef = ref()
const permTreeRef = ref()
const loading = ref(false)
const ids = ref<number[]>([])
const total = ref(0)
const personinchargeList = ref<any[]>([])
const queryParams = reactive<any>({
pageNum: 1,
pageSize: 10,
times: [],
Undertaker: ''
})
// 角色表格数据
const roleList = ref<RolePageVO[]>()
// 弹窗
const dialog = reactive({
title: '',
visible: false
})
const permKeywords = ref('')
// 获取数据
function fetchData() {
loading.value = true
BusinessRegisterdetail(queryParams)
.then((res: any) => {
roleList.value = res.data
total.value = res.total
})
.finally(() => {
loading.value = false
})
}
// 查询(重置页码后获取数据)
function handleQuery() {
queryParams.pageNum = 1
fetchData()
}
// 重置查询
function handleResetQuery() {
if (queryFormRef.value) queryFormRef.value.resetFields()
queryParams.pageNum = 1
fetchData()
}
// 行复选框选中
function handleSelectionChange(selection: any) {
ids.value = selection.map((item: any) => item.id)
}
// 打开角色弹窗
function handleOpenDialog(roleId?: string) {
dialog.visible = true
if (roleId) {
functionDialogBox(
PreRegistrationForm,
{},
{
title: '编辑预立案登记',
width: '900',
ok(value: any) {
console.log('value', value)
}
// cancel() {
// console.log("value");
// },
}
)
} else {
functionDialogBox(
PreRegistrationForm,
{},
{
title: '新增预立案登记',
width: '900',
ok(value: any) {
console.log('value', value)
handleSubmit(value)
}
// cancel() {
// console.log("value");
// },
}
)
}
}
// 提交角色表单
function handleSubmit(data: any) {
loading.value = true
const roleId = data.id
if (roleId) {
// RoleAPI.update(roleId, formData)
// .then(() => {
// ElMessage.success('修改成功')
// handleCloseDialog()
// handleResetQuery()
// })
// .finally(() => (loading.value = false))
} else {
BusinessRegister({
...data,
client_username: JSON.stringify(data.client_username),
party_username: JSON.stringify(data.party_username)
})
.then(() => {
ElMessage.success('新增成功')
handleResetQuery()
})
.finally(() => (loading.value = false))
}
}
const onUserDeleteDepartment = (id: string) => {
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(
() => {
loading.value = true
UserDeleteDepartment(id)
.then(() => {
ElMessage.success('删除成功')
handleResetQuery()
})
.finally(() => (loading.value = false))
},
() => {
ElMessage.info('已取消删除')
}
)
}
// 删除角色
function handleDelete(roleId?: number) {
const roleIds = [roleId || ids.value].join(',')
if (!roleIds) {
ElMessage.warning('请勾选删除项')
return
}
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(
() => {
loading.value = true
RoleAPI.deleteByIds(roleIds)
.then(() => {
ElMessage.success('删除成功')
handleResetQuery()
})
.finally(() => (loading.value = false))
},
() => {
ElMessage.info('已取消删除')
}
)
}
const DepartmentList = () => {
UserPersonneldisplay().then((res: any) => {
personinchargeList.value = res.data
})
}
// 权限筛选
watch(permKeywords, (val) => {
permTreeRef.value!.filter(val)
})
onMounted(() => {
handleQuery()
DepartmentList()
})
</script>

View File

@@ -1,55 +1,55 @@
import vue from "@vitejs/plugin-vue";
import { type ConfigEnv, type UserConfig, loadEnv, defineConfig, type PluginOption } from "vite";
import vue from '@vitejs/plugin-vue'
import { type ConfigEnv, type UserConfig, loadEnv, defineConfig, type PluginOption } from 'vite'
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { mockDevServerPlugin } from "vite-plugin-mock-dev-server";
import { mockDevServerPlugin } from 'vite-plugin-mock-dev-server'
import UnoCSS from "unocss/vite";
import { resolve } from "path";
import { name, version, engines, dependencies, devDependencies } from "./package.json";
import UnoCSS from 'unocss/vite'
import { resolve } from 'path'
import { name, version, engines, dependencies, devDependencies } from './package.json'
// 平台的名称、版本、运行所需的 node 版本、依赖、构建时间的类型提示
const __APP_INFO__ = {
pkg: { name, version, engines, dependencies, devDependencies },
buildTimestamp: Date.now(),
};
buildTimestamp: Date.now()
}
const pathSrc = resolve(__dirname, "src");
const pathSrc = resolve(__dirname, 'src')
// Vite配置 https://cn.vitejs.dev/config
export default defineConfig(({ mode }: ConfigEnv) => {
const env = loadEnv(mode, process.cwd());
const isProduction = mode === "production";
const env = loadEnv(mode, process.cwd())
const isProduction = mode === 'production'
return {
base: "./", // 设置为相对路径支持直接打开index.html
base: './', // 设置为相对路径支持直接打开index.html
resolve: {
alias: {
"@": pathSrc,
},
'@': pathSrc
}
},
css: {
preprocessorOptions: {
// 定义全局 SCSS 变量
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`,
},
},
additionalData: `@use "@/styles/variables.scss" as *;`
}
}
},
server: {
host: "0.0.0.0",
host: '0.0.0.0',
port: +(env.VITE_APP_PORT as string),
open: true,
proxy: {
"/dev-api/api2": {
'/dev-api/api2': {
changeOrigin: true,
target: "http://8.137.99.82:8006",
target: 'http://192.168.31.69:8006',
rewrite: (path: string) => {
return path.replace(/^\/dev-api\/api2/, "");
},
return path.replace(/^\/dev-api\/api2/, '')
}
},
// 代理 /dev-api 的请求
[env.VITE_APP_BASE_API as string]: {
@@ -57,163 +57,163 @@ export default defineConfig(({ mode }: ConfigEnv) => {
// 代理目标地址https://api.youlai.tech
target: env.VITE_APP_API_URL as string,
rewrite: (path: string) => {
return path.replace(new RegExp("^" + (env.VITE_APP_BASE_API as string)), "");
},
},
},
return path.replace(new RegExp('^' + (env.VITE_APP_BASE_API as string)), '')
}
}
}
},
plugins: [
vue(),
...(env.VITE_MOCK_DEV_SERVER === "true" ? [mockDevServerPlugin()] : []),
...(env.VITE_MOCK_DEV_SERVER === 'true' ? [mockDevServerPlugin()] : []),
UnoCSS(),
// API 自动导入
AutoImport({
// 导入 Vue 函数ref, reactive, toRef 等
imports: ["vue", "@vueuse/core", "pinia", "vue-router", "vue-i18n"],
imports: ['vue', '@vueuse/core', 'pinia', 'vue-router', 'vue-i18n'],
resolvers: [
// 导入 Element Plus函数ElMessage, ElMessageBox 等
ElementPlusResolver({ importStyle: "sass" }),
ElementPlusResolver({ importStyle: 'sass' })
],
eslintrc: {
enabled: false,
filepath: "./.eslintrc-auto-import.json",
globalsPropValue: true,
filepath: './.eslintrc-auto-import.json',
globalsPropValue: true
},
vueTemplate: true,
// 导入函数类型声明文件路径 (false:关闭自动生成)
dts: false,
dts: false
// dts: "src/types/auto-imports.d.ts",
}),
// 组件自动导入
Components({
resolvers: [
// 导入 Element Plus 组件
ElementPlusResolver({ importStyle: "sass" }),
ElementPlusResolver({ importStyle: 'sass' })
],
// 指定自定义组件位置(默认:src/components)
dirs: ["src/components", "src/**/components"],
dirs: ['src/components', 'src/**/components'],
// 导入组件类型声明文件路径 (false:关闭自动生成)
dts: false,
dts: false
// dts: "src/types/components.d.ts",
}),
})
],
// 预加载项目必需的组件
optimizeDeps: {
include: [
"vue",
"vue-router",
"element-plus",
"pinia",
"axios",
"@vueuse/core",
"codemirror-editor-vue3",
"default-passive-events",
"exceljs",
"path-to-regexp",
"echarts/core",
"echarts/renderers",
"echarts/charts",
"echarts/components",
"vue-i18n",
"nprogress",
"sortablejs",
"qs",
"path-browserify",
"@stomp/stompjs",
"@element-plus/icons-vue",
"element-plus/es",
"element-plus/es/locale/lang/en",
"element-plus/es/locale/lang/zh-cn",
"element-plus/es/components/alert/style/index",
"element-plus/es/components/avatar/style/index",
"element-plus/es/components/backtop/style/index",
"element-plus/es/components/badge/style/index",
"element-plus/es/components/base/style/index",
"element-plus/es/components/breadcrumb-item/style/index",
"element-plus/es/components/breadcrumb/style/index",
"element-plus/es/components/button/style/index",
"element-plus/es/components/card/style/index",
"element-plus/es/components/cascader/style/index",
"element-plus/es/components/checkbox-group/style/index",
"element-plus/es/components/checkbox/style/index",
"element-plus/es/components/col/style/index",
"element-plus/es/components/color-picker/style/index",
"element-plus/es/components/config-provider/style/index",
"element-plus/es/components/date-picker/style/index",
"element-plus/es/components/descriptions-item/style/index",
"element-plus/es/components/descriptions/style/index",
"element-plus/es/components/dialog/style/index",
"element-plus/es/components/divider/style/index",
"element-plus/es/components/drawer/style/index",
"element-plus/es/components/dropdown-item/style/index",
"element-plus/es/components/dropdown-menu/style/index",
"element-plus/es/components/dropdown/style/index",
"element-plus/es/components/empty/style/index",
"element-plus/es/components/form-item/style/index",
"element-plus/es/components/form/style/index",
"element-plus/es/components/icon/style/index",
"element-plus/es/components/image-viewer/style/index",
"element-plus/es/components/image/style/index",
"element-plus/es/components/input-number/style/index",
"element-plus/es/components/input-tag/style/index",
"element-plus/es/components/input/style/index",
"element-plus/es/components/link/style/index",
"element-plus/es/components/loading/style/index",
"element-plus/es/components/menu-item/style/index",
"element-plus/es/components/menu/style/index",
"element-plus/es/components/message-box/style/index",
"element-plus/es/components/message/style/index",
"element-plus/es/components/notification/style/index",
"element-plus/es/components/option/style/index",
"element-plus/es/components/pagination/style/index",
"element-plus/es/components/popover/style/index",
"element-plus/es/components/progress/style/index",
"element-plus/es/components/radio-button/style/index",
"element-plus/es/components/radio-group/style/index",
"element-plus/es/components/radio/style/index",
"element-plus/es/components/row/style/index",
"element-plus/es/components/scrollbar/style/index",
"element-plus/es/components/select/style/index",
"element-plus/es/components/skeleton-item/style/index",
"element-plus/es/components/skeleton/style/index",
"element-plus/es/components/step/style/index",
"element-plus/es/components/steps/style/index",
"element-plus/es/components/sub-menu/style/index",
"element-plus/es/components/switch/style/index",
"element-plus/es/components/tab-pane/style/index",
"element-plus/es/components/table-column/style/index",
"element-plus/es/components/table/style/index",
"element-plus/es/components/tabs/style/index",
"element-plus/es/components/tag/style/index",
"element-plus/es/components/text/style/index",
"element-plus/es/components/time-picker/style/index",
"element-plus/es/components/time-select/style/index",
"element-plus/es/components/timeline-item/style/index",
"element-plus/es/components/timeline/style/index",
"element-plus/es/components/tooltip/style/index",
"element-plus/es/components/tree-select/style/index",
"element-plus/es/components/tree/style/index",
"element-plus/es/components/upload/style/index",
"element-plus/es/components/watermark/style/index",
"element-plus/es/components/checkbox-button/style/index",
"element-plus/es/components/space/style/index",
],
'vue',
'vue-router',
'element-plus',
'pinia',
'axios',
'@vueuse/core',
'codemirror-editor-vue3',
'default-passive-events',
'exceljs',
'path-to-regexp',
'echarts/core',
'echarts/renderers',
'echarts/charts',
'echarts/components',
'vue-i18n',
'nprogress',
'sortablejs',
'qs',
'path-browserify',
'@stomp/stompjs',
'@element-plus/icons-vue',
'element-plus/es',
'element-plus/es/locale/lang/en',
'element-plus/es/locale/lang/zh-cn',
'element-plus/es/components/alert/style/index',
'element-plus/es/components/avatar/style/index',
'element-plus/es/components/backtop/style/index',
'element-plus/es/components/badge/style/index',
'element-plus/es/components/base/style/index',
'element-plus/es/components/breadcrumb-item/style/index',
'element-plus/es/components/breadcrumb/style/index',
'element-plus/es/components/button/style/index',
'element-plus/es/components/card/style/index',
'element-plus/es/components/cascader/style/index',
'element-plus/es/components/checkbox-group/style/index',
'element-plus/es/components/checkbox/style/index',
'element-plus/es/components/col/style/index',
'element-plus/es/components/color-picker/style/index',
'element-plus/es/components/config-provider/style/index',
'element-plus/es/components/date-picker/style/index',
'element-plus/es/components/descriptions-item/style/index',
'element-plus/es/components/descriptions/style/index',
'element-plus/es/components/dialog/style/index',
'element-plus/es/components/divider/style/index',
'element-plus/es/components/drawer/style/index',
'element-plus/es/components/dropdown-item/style/index',
'element-plus/es/components/dropdown-menu/style/index',
'element-plus/es/components/dropdown/style/index',
'element-plus/es/components/empty/style/index',
'element-plus/es/components/form-item/style/index',
'element-plus/es/components/form/style/index',
'element-plus/es/components/icon/style/index',
'element-plus/es/components/image-viewer/style/index',
'element-plus/es/components/image/style/index',
'element-plus/es/components/input-number/style/index',
'element-plus/es/components/input-tag/style/index',
'element-plus/es/components/input/style/index',
'element-plus/es/components/link/style/index',
'element-plus/es/components/loading/style/index',
'element-plus/es/components/menu-item/style/index',
'element-plus/es/components/menu/style/index',
'element-plus/es/components/message-box/style/index',
'element-plus/es/components/message/style/index',
'element-plus/es/components/notification/style/index',
'element-plus/es/components/option/style/index',
'element-plus/es/components/pagination/style/index',
'element-plus/es/components/popover/style/index',
'element-plus/es/components/progress/style/index',
'element-plus/es/components/radio-button/style/index',
'element-plus/es/components/radio-group/style/index',
'element-plus/es/components/radio/style/index',
'element-plus/es/components/row/style/index',
'element-plus/es/components/scrollbar/style/index',
'element-plus/es/components/select/style/index',
'element-plus/es/components/skeleton-item/style/index',
'element-plus/es/components/skeleton/style/index',
'element-plus/es/components/step/style/index',
'element-plus/es/components/steps/style/index',
'element-plus/es/components/sub-menu/style/index',
'element-plus/es/components/switch/style/index',
'element-plus/es/components/tab-pane/style/index',
'element-plus/es/components/table-column/style/index',
'element-plus/es/components/table/style/index',
'element-plus/es/components/tabs/style/index',
'element-plus/es/components/tag/style/index',
'element-plus/es/components/text/style/index',
'element-plus/es/components/time-picker/style/index',
'element-plus/es/components/time-select/style/index',
'element-plus/es/components/timeline-item/style/index',
'element-plus/es/components/timeline/style/index',
'element-plus/es/components/tooltip/style/index',
'element-plus/es/components/tree-select/style/index',
'element-plus/es/components/tree/style/index',
'element-plus/es/components/upload/style/index',
'element-plus/es/components/watermark/style/index',
'element-plus/es/components/checkbox-button/style/index',
'element-plus/es/components/space/style/index'
]
},
// 构建配置
build: {
chunkSizeWarningLimit: 2000, // 消除打包大小超过500kb警告
minify: isProduction ? ("terser" as const) : false, // 只在生产环境启用压缩
minify: isProduction ? ('terser' as const) : false, // 只在生产环境启用压缩
terserOptions: isProduction
? {
compress: {
keep_infinity: true, // 防止 Infinity 被压缩成 1/0这可能会导致 Chrome 上的性能问题
drop_console: true, // 生产环境去除 console.log, console.warn, console.error 等
drop_debugger: true, // 生产环境去除 debugger
pure_funcs: ["console.log", "console.info"], // 移除指定的函数调用
pure_funcs: ['console.log', 'console.info'] // 移除指定的函数调用
},
format: {
comments: false, // 删除注释
},
comments: false // 删除注释
}
}
: {},
rollupOptions: {
@@ -222,28 +222,28 @@ export default defineConfig(({ mode }: ConfigEnv) => {
// "vue-i18n": ["vue-i18n"],
// },
// 用于从入口点创建的块的打包输出格式[name]表示文件名,[hash]表示该文件内容hash值
entryFileNames: "js/[name].[hash].js",
entryFileNames: 'js/[name].[hash].js',
// 用于命名代码拆分时创建的共享块的输出命名
chunkFileNames: "js/[name].[hash].js",
chunkFileNames: 'js/[name].[hash].js',
// 用于输出静态资源的命名,[ext]表示文件扩展名
assetFileNames: (assetInfo: any) => {
const info = assetInfo.name.split(".");
let extType = info[info.length - 1];
const info = assetInfo.name.split('.')
let extType = info[info.length - 1]
// console.log('文件信息', assetInfo.name)
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(assetInfo.name)) {
extType = "media";
extType = 'media'
} else if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(assetInfo.name)) {
extType = "img";
extType = 'img'
} else if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(assetInfo.name)) {
extType = "fonts";
extType = 'fonts'
}
return `${extType}/[name].[hash].[ext]`;
},
},
},
return `${extType}/[name].[hash].[ext]`
}
}
}
},
define: {
__APP_INFO__: JSON.stringify(__APP_INFO__),
},
};
});
__APP_INFO__: JSON.stringify(__APP_INFO__)
}
}
})