更新路由以及静态页面完成
This commit is contained in:
BIN
public/img/logo.png
Normal file
BIN
public/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@@ -161,14 +161,6 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
title: "工资/奖金变更",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "role",
|
||||
name: "FinanceRole",
|
||||
component: () => import("@/views/system/role/index.vue"),
|
||||
meta: {
|
||||
title: "角色管理",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// 业务管理模块
|
||||
@@ -197,14 +189,6 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
title: "预立案登记",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "projectManagement",
|
||||
name: "ProjectManagement",
|
||||
component: () => import("@/views/business/preRegistration/index.vue"),
|
||||
meta: {
|
||||
title: "立项管理",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// 案件管理模块
|
||||
@@ -220,17 +204,9 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "user",
|
||||
name: "CaseUser",
|
||||
component: () => import("@/views/system/user/index.vue"),
|
||||
component: () => import("@/views/case/index.vue"),
|
||||
meta: {
|
||||
title: "人事管理",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "role",
|
||||
name: "CaseRole",
|
||||
component: () => import("@/views/system/role/index.vue"),
|
||||
meta: {
|
||||
title: "角色管理",
|
||||
title: "案件管理",
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -270,7 +246,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "index",
|
||||
name: "StampPerformanceIndex",
|
||||
component: () => import("@/views/stamp-application/index.vue"),
|
||||
component: () => import("@/views/performance/list/index.vue"),
|
||||
meta: {
|
||||
title: "业绩展示",
|
||||
},
|
||||
@@ -291,7 +267,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "index",
|
||||
name: "RegistrationIndex",
|
||||
component: () => import("@/views/stamp-application/index.vue"),
|
||||
component: () => import("@/views/registration/index.vue"),
|
||||
meta: {
|
||||
title: "入库登记",
|
||||
},
|
||||
@@ -312,7 +288,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "index",
|
||||
name: "NoticeIndex",
|
||||
component: () => import("@/views/stamp-application/index.vue"),
|
||||
component: () => import("@/views/notice/index.vue"),
|
||||
meta: {
|
||||
title: "公告管理",
|
||||
},
|
||||
@@ -333,7 +309,7 @@ export const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "index",
|
||||
name: "LawyerFileIndex",
|
||||
component: () => import("@/views/stamp-application/index.vue"),
|
||||
component: () => import("@/views/lawyer/index.vue"),
|
||||
meta: {
|
||||
title: "律所标准文件",
|
||||
},
|
||||
|
||||
@@ -26,6 +26,22 @@
|
||||
</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"
|
||||
@@ -76,7 +92,13 @@
|
||||
:size="drawerSize"
|
||||
@close="handleCloseDialog"
|
||||
>
|
||||
<el-form ref="userFormRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<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"
|
||||
@@ -134,7 +156,21 @@
|
||||
/>
|
||||
</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>
|
||||
@@ -212,6 +248,11 @@ const formData = reactive<UserForm>({
|
||||
status: 1,
|
||||
});
|
||||
|
||||
// 登记表格数据
|
||||
const formDataTender = reactive<UserForm>({
|
||||
status: 1,
|
||||
});
|
||||
|
||||
// 下拉选项数据
|
||||
const deptOptions = ref<OptionType[]>();
|
||||
const roleOptions = ref<OptionType[]>();
|
||||
@@ -273,6 +314,16 @@ const rules = reactive({
|
||||
],
|
||||
});
|
||||
|
||||
const rulesTender = reactive({
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: "案件名不能为空",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// ==================== 数据加载 ====================
|
||||
|
||||
/**
|
||||
@@ -346,8 +397,9 @@ function handleResetPassword(row: UserPageVO): void {
|
||||
* 打开用户表单弹窗
|
||||
* @param id 用户ID(编辑时传入)
|
||||
*/
|
||||
async function handleOpenDialog(id?: string): Promise<void> {
|
||||
async function handleOpenDialog(titleString: string, id?: string): Promise<void> {
|
||||
dialog.visible = true;
|
||||
dialog.title = titleString;
|
||||
|
||||
// 并行加载下拉选项数据
|
||||
try {
|
||||
@@ -362,7 +414,6 @@ async function handleOpenDialog(id?: string): Promise<void> {
|
||||
|
||||
// 编辑:加载用户数据
|
||||
if (id) {
|
||||
dialog.title = "修改用户";
|
||||
try {
|
||||
const data = await UserAPI.getFormData(id);
|
||||
Object.assign(formData, data);
|
||||
@@ -370,9 +421,6 @@ async function handleOpenDialog(id?: string): Promise<void> {
|
||||
ElMessage.error("加载用户数据失败");
|
||||
console.error("加载用户数据失败:", error);
|
||||
}
|
||||
} else {
|
||||
// 新增:设置默认值
|
||||
dialog.title = "新增用户";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ const handleSaveDraft = () => {
|
||||
<style scoped>
|
||||
.pre-case-registration {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
|
||||
70
src/views/case/components/DeptTree.vue
Normal file
70
src/views/case/components/DeptTree.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<!-- 部门树 -->
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<el-input v-model="deptName" placeholder="部门名称" clearable>
|
||||
<template #prefix>
|
||||
<el-icon><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tree
|
||||
ref="deptTreeRef"
|
||||
class="mt-2"
|
||||
:data="deptList"
|
||||
:props="{ children: 'children', label: 'label', disabled: '' }"
|
||||
:expand-on-click-node="false"
|
||||
:filter-node-method="handleFilter"
|
||||
default-expand-all
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import DeptAPI from "@/api/system/dept-api";
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const deptList = ref<OptionType[]>(); // 部门列表
|
||||
const deptTreeRef = ref(); // 部门树
|
||||
const deptName = ref(); // 部门名称
|
||||
|
||||
const emits = defineEmits(["node-click"]);
|
||||
|
||||
const deptId = useVModel(props, "modelValue", emits);
|
||||
|
||||
watchEffect(
|
||||
() => {
|
||||
deptTreeRef.value.filter(deptName.value);
|
||||
},
|
||||
{
|
||||
flush: "post", // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 部门筛选
|
||||
*/
|
||||
function handleFilter(value: string, data: any) {
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
return data.label.indexOf(value) !== -1;
|
||||
}
|
||||
|
||||
/** 部门树节点 Click */
|
||||
function handleNodeClick(data: { [key: string]: any }) {
|
||||
deptId.value = data.value;
|
||||
emits("node-click");
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
DeptAPI.getOptions().then((data) => {
|
||||
deptList.value = data;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
198
src/views/case/components/UserImport.vue
Normal file
198
src/views/case/components/UserImport.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
:align-center="true"
|
||||
title="导入数据"
|
||||
width="600px"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-scrollbar max-height="60vh">
|
||||
<el-form
|
||||
ref="importFormRef"
|
||||
style="padding-right: var(--el-dialog-padding-primary)"
|
||||
:model="importFormData"
|
||||
:rules="importFormRules"
|
||||
>
|
||||
<el-form-item label="文件名" prop="files">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="importFormData.files"
|
||||
class="w-full"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:drag="true"
|
||||
:limit="1"
|
||||
:auto-upload="false"
|
||||
:on-exceed="handleFileExceed"
|
||||
>
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
格式为*.xlsx / *.xls,文件不超过一个
|
||||
<el-link
|
||||
type="primary"
|
||||
icon="download"
|
||||
underline="never"
|
||||
@click="handleDownloadTemplate"
|
||||
>
|
||||
下载模板
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
<template #footer>
|
||||
<div style="padding-right: var(--el-dialog-padding-primary)">
|
||||
<el-button v-if="resultData.length > 0" type="primary" @click="handleShowResult">
|
||||
错误信息
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="importFormData.files.length === 0"
|
||||
@click="handleUpload"
|
||||
>
|
||||
确 定
|
||||
</el-button>
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="resultVisible" title="导入结果" width="600px">
|
||||
<el-alert
|
||||
:title="`导入结果:${invalidCount}条无效数据,${validCount}条有效数据`"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
/>
|
||||
<el-table :data="resultData" style="width: 100%; max-height: 400px">
|
||||
<el-table-column prop="index" align="center" width="100" type="index" label="序号" />
|
||||
<el-table-column prop="message" label="错误信息" width="400">
|
||||
<template #default="scope">
|
||||
{{ scope.row }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleCloseResult">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, type UploadUserFile } from "element-plus";
|
||||
import UserAPI from "@/api/system/user-api";
|
||||
import { ApiCodeEnum } from "@/enums/api/code-enum";
|
||||
|
||||
const emit = defineEmits(["import-success"]);
|
||||
const visible = defineModel("modelValue", {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
});
|
||||
|
||||
const resultVisible = ref(false);
|
||||
const resultData = ref<string[]>([]);
|
||||
const invalidCount = ref(0);
|
||||
const validCount = ref(0);
|
||||
|
||||
const importFormRef = ref(null);
|
||||
const uploadRef = ref(null);
|
||||
|
||||
const importFormData = reactive<{
|
||||
files: UploadUserFile[];
|
||||
}>({
|
||||
files: [],
|
||||
});
|
||||
|
||||
watch(visible, (newValue) => {
|
||||
if (newValue) {
|
||||
resultData.value = [];
|
||||
resultVisible.value = false;
|
||||
invalidCount.value = 0;
|
||||
validCount.value = 0;
|
||||
}
|
||||
});
|
||||
|
||||
const importFormRules = {
|
||||
files: [{ required: true, message: "文件不能为空", trigger: "blur" }],
|
||||
};
|
||||
|
||||
// 文件超出个数限制
|
||||
const handleFileExceed = () => {
|
||||
ElMessage.warning("只能上传一个文件");
|
||||
};
|
||||
|
||||
// 下载导入模板
|
||||
const handleDownloadTemplate = () => {
|
||||
UserAPI.downloadTemplate().then((response: any) => {
|
||||
const fileData = response.data;
|
||||
const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]);
|
||||
const fileType =
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
|
||||
|
||||
const blob = new Blob([fileData], { type: fileType });
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
const downloadLink = document.createElement("a");
|
||||
downloadLink.href = downloadUrl;
|
||||
downloadLink.download = fileName;
|
||||
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
|
||||
document.body.removeChild(downloadLink);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
});
|
||||
};
|
||||
|
||||
// 上传文件
|
||||
const handleUpload = async () => {
|
||||
if (!importFormData.files.length) {
|
||||
ElMessage.warning("请选择文件");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await UserAPI.import("1", importFormData.files[0].raw as File);
|
||||
if (result.code === ApiCodeEnum.SUCCESS && result.invalidCount === 0) {
|
||||
ElMessage.success("导入成功,导入数据:" + result.validCount + "条");
|
||||
emit("import-success");
|
||||
handleClose();
|
||||
} else {
|
||||
ElMessage.error("上传失败");
|
||||
resultVisible.value = true;
|
||||
resultData.value = result.messageList;
|
||||
invalidCount.value = result.invalidCount;
|
||||
validCount.value = result.validCount;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
ElMessage.error("上传失败:" + error);
|
||||
}
|
||||
};
|
||||
|
||||
// 显示错误信息
|
||||
const handleShowResult = () => {
|
||||
resultVisible.value = true;
|
||||
};
|
||||
|
||||
// 关闭错误信息弹窗
|
||||
const handleCloseResult = () => {
|
||||
resultVisible.value = false;
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const handleClose = () => {
|
||||
importFormData.files.length = 0;
|
||||
visible.value = false;
|
||||
};
|
||||
</script>
|
||||
682
src/views/case/index.vue
Normal file
682
src/views/case/index.vue
Normal file
@@ -0,0 +1,682 @@
|
||||
<!-- 用户管理 -->
|
||||
<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="status">
|
||||
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 100px">
|
||||
<el-option label="正常" :value="1" />
|
||||
<el-option label="禁用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="queryParams.createTime"
|
||||
:editable="false"
|
||||
type="daterange"
|
||||
range-separator="~"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="截止时间"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</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
|
||||
v-hasPerm="['sys:user:add']"
|
||||
type="success"
|
||||
icon="plus"
|
||||
@click="handleOpenDialog()"
|
||||
>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPerm="'sys:user:delete'"
|
||||
type="danger"
|
||||
icon="delete"
|
||||
:disabled="!hasSelection"
|
||||
@click="handleDelete()"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="data-table__toolbar--tools">
|
||||
<el-button v-hasPerm="'sys:user:import'" icon="upload" @click="handleOpenImportDialog">
|
||||
导入
|
||||
</el-button>
|
||||
|
||||
<el-button v-hasPerm="'sys:user:export'" icon="download" @click="handleExport">
|
||||
导出
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="100" align="center">
|
||||
<template #default="scope">
|
||||
<DictLabel v-model="scope.row.gender" code="gender" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="相对方名称" width="120" align="center" prop="deptName" />
|
||||
<el-table-column label="项目简述" align="center" prop="mobile" width="120" />
|
||||
<el-table-column label="负责人" align="center" prop="email" width="160">
|
||||
<template #default="scope">
|
||||
<span @click="handleOpenChangeResponsibleDialog(scope.row)">
|
||||
{{ scope.row.responsibleName || "未分配" }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收费情况" align="center" prop="status" width="80">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">
|
||||
{{ scope.row.status == 1 ? "正常" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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" 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" 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>
|
||||
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
v-model:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="fetchUserList"
|
||||
/>
|
||||
</el-card>
|
||||
<!-- 用户导入 -->
|
||||
<UserImport v-model="importDialogVisible" @import-success="handleQuery()" />
|
||||
</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";
|
||||
import DeptAPI from "@/api/system/dept-api";
|
||||
import RoleAPI from "@/api/system/role-api";
|
||||
import fileApi from "@/api/file-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";
|
||||
|
||||
// ==================== 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 currentCase = ref(null);
|
||||
|
||||
// 负责人
|
||||
const changeResponsible = ref("");
|
||||
|
||||
// 打开负责人更改弹窗
|
||||
function handleOpenChangeResponsibleDialog(row) {
|
||||
ElMessageBox.prompt(`请输入案件【${row.username}】的新负责人`, "负责人更改", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
inputPattern: /.{1,}/,
|
||||
inputErrorMessage: "负责人不能为空",
|
||||
})
|
||||
.then(({ value }) => {
|
||||
return UserAPI.resetPassword(row.id, value);
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success("负责人更改成功");
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error !== "cancel") {
|
||||
ElMessage.error("负责人更改失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 更改负责人
|
||||
function handleChangeResponsible() {
|
||||
if (!changeResponsible.value.trim()) {
|
||||
ElMessage.warning("请输入负责人");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 这里应该调用案件管理API更新负责人
|
||||
// 更新本地数据
|
||||
if (currentCase.value) {
|
||||
currentCase.value.responsibleName = changeResponsible.value;
|
||||
// 更新列表中的数据
|
||||
if (pageData.value && pageData.value.length > 0) {
|
||||
const index = pageData.value.findIndex((item) => item.id === currentCase.value.id);
|
||||
if (index !== -1) {
|
||||
pageData.value[index].responsibleName = changeResponsible.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
ElMessage.success("负责人更改成功");
|
||||
changeResponsibleDialogVisible.value = false;
|
||||
changeResponsible.value = "";
|
||||
currentCase.value = null;
|
||||
} catch (error) {
|
||||
ElMessage.error("负责人更改失败");
|
||||
console.error("更改负责人失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive<UserForm>({
|
||||
educationResume: [
|
||||
{
|
||||
education: [],
|
||||
// 毕业院校
|
||||
institute: "",
|
||||
// 专业
|
||||
major: "",
|
||||
// 学历
|
||||
educationLevel: "",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 下拉选项数据
|
||||
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",
|
||||
},
|
||||
],
|
||||
educationResume: [
|
||||
{
|
||||
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 { selectedIds, hasSelection, 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(id?: string): Promise<void> {
|
||||
dialog.visible = true;
|
||||
|
||||
// 并行加载下拉选项数据
|
||||
try {
|
||||
[roleOptions.value, deptOptions.value] = await Promise.all([
|
||||
RoleAPI.getOptions(),
|
||||
DeptAPI.getOptions(),
|
||||
]);
|
||||
} catch (error) {
|
||||
ElMessage.error("加载选项数据失败");
|
||||
console.error("加载选项数据失败:", error);
|
||||
}
|
||||
|
||||
// 编辑:加载用户数据
|
||||
if (id) {
|
||||
dialog.title = "修改用户";
|
||||
try {
|
||||
const data = await UserAPI.getFormData(id);
|
||||
Object.assign(formData, data);
|
||||
} catch (error) {
|
||||
ElMessage.error("加载用户数据失败");
|
||||
console.error("加载用户数据失败:", error);
|
||||
}
|
||||
} else {
|
||||
// 新增:设置默认值
|
||||
dialog.title = "新增用户";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭用户表单弹窗
|
||||
*/
|
||||
function handleCloseDialog(): void {
|
||||
dialog.visible = false;
|
||||
userFormRef.value.resetFields();
|
||||
userFormRef.value.clearValidate();
|
||||
|
||||
// 重置表单数据
|
||||
formData.id = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交用户表单(防抖)
|
||||
*/
|
||||
const handleSubmit = useDebounceFn(async () => {
|
||||
const valid = await userFormRef.value.validate().catch(() => false);
|
||||
if (!valid) return;
|
||||
|
||||
const userId = formData.id;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
if (userId) {
|
||||
await UserAPI.update(userId, formData);
|
||||
ElMessage.success("修改用户成功");
|
||||
} else {
|
||||
await UserAPI.create(formData);
|
||||
ElMessage.success("新增用户成功");
|
||||
}
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
} catch (error) {
|
||||
ElMessage.error(userId ? "修改用户失败" : "新增用户失败");
|
||||
console.error("提交用户表单失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param id 用户ID(单个删除时传入)
|
||||
*/
|
||||
function handleDelete(id?: string): void {
|
||||
const userIds = id ? id : selectedIds.value.join(",");
|
||||
|
||||
if (!userIds) {
|
||||
ElMessage.warning("请勾选删除项");
|
||||
return;
|
||||
}
|
||||
|
||||
// 安全检查:防止删除当前登录用户
|
||||
const currentUserId = userStore.userInfo?.userId;
|
||||
if (currentUserId) {
|
||||
const isCurrentUserInList = id
|
||||
? id === currentUserId
|
||||
: selectedIds.value.some((selectedId) => String(selectedId) === currentUserId);
|
||||
|
||||
if (isCurrentUserInList) {
|
||||
ElMessage.error("不能删除当前登录用户");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("确认删除选中的用户吗?", "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
await UserAPI.deleteByIds(userIds);
|
||||
ElMessage.success("删除成功");
|
||||
handleResetQuery();
|
||||
} catch (error) {
|
||||
ElMessage.error("删除失败");
|
||||
console.error("删除用户失败:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消操作,无需处理
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 上传文件 ====================
|
||||
|
||||
/**
|
||||
* 上传前的校验
|
||||
* @param file 上传的文件对象
|
||||
*/
|
||||
function handleBeforeUpload(file: File): boolean {
|
||||
// 可以在这里添加文件类型和大小的校验
|
||||
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||
if (!isLt10M) {
|
||||
ElMessage.error("上传文件大小不能超过 10MB!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件上传成功后的回调
|
||||
* @param res 上传响应数据
|
||||
* @param file 上传的文件对象
|
||||
* @param field 表单字段名
|
||||
*/
|
||||
function handleFileUploadSuccess(res: any, file: File, field: string): void {
|
||||
formData[field] = res.data.url;
|
||||
userFormRef.value.clearValidate(field);
|
||||
ElMessage.success("文件上传成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除已上传的文件
|
||||
* @param field 表单字段名
|
||||
*/
|
||||
function removeFile(field: string): void {
|
||||
formData[field] = undefined;
|
||||
ElMessage.success("文件已删除");
|
||||
}
|
||||
|
||||
// ==================== 导入导出 ====================
|
||||
|
||||
/**
|
||||
* 打开导入弹窗
|
||||
*/
|
||||
function handleOpenImportDialog(): void {
|
||||
importDialogVisible.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户列表
|
||||
*/
|
||||
async function handleExport(): Promise<void> {
|
||||
try {
|
||||
const response = await UserAPI.export(queryParams);
|
||||
const fileData = response.data;
|
||||
const contentDisposition = response.headers["content-disposition"];
|
||||
const fileName = decodeURI(contentDisposition.split(";")[1].split("=")[1]);
|
||||
const fileType =
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
|
||||
|
||||
// 创建下载链接
|
||||
const blob = new Blob([fileData], { type: fileType });
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const downloadLink = document.createElement("a");
|
||||
downloadLink.href = downloadUrl;
|
||||
downloadLink.download = fileName;
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
|
||||
// 清理
|
||||
document.body.removeChild(downloadLink);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
|
||||
ElMessage.success("导出成功");
|
||||
} catch (error) {
|
||||
ElMessage.error("导出失败");
|
||||
console.error("导出用户列表失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 生命周期 ====================
|
||||
|
||||
/**
|
||||
* 组件挂载时初始化数据
|
||||
*
|
||||
* 注意:这里会先加载列表数据,如果 URL 中有 AI 参数(如搜索关键字),
|
||||
* useAiAction 会在 nextTick 中再次执行搜索,这是预期行为
|
||||
*/
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 学业简历表格样式 -->
|
||||
<style scoped>
|
||||
.education-resume-table {
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.education-resume-header {
|
||||
display: flex;
|
||||
background-color: #f5f7fa;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
font-weight: bold;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.education-resume-row {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.education-resume-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table-col {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.date-col {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.school-col {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.major-col {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.degree-col {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.action-col {
|
||||
width: 10%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.education-resume-actions {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* 表单元素样式调整 */
|
||||
.education-resume-row .el-input,
|
||||
.education-resume-row .el-select,
|
||||
.education-resume-row .el-date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
138
src/views/lawyer/index.vue
Normal file
138
src/views/lawyer/index.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="performance-list-container">
|
||||
<el-button type="primary" icon="edit" style="margin-bottom: 20px">新增律所文件</el-button>
|
||||
<div
|
||||
v-for="(item, index) in performanceList"
|
||||
:key="index"
|
||||
class="performance-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<div class="item-header">
|
||||
<img :src="item.imageUrl" :alt="item.title" class="item-image" />
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<h3 class="item-title">{{ item.title }}</h3>
|
||||
<p class="item-description">{{ item.description }}</p>
|
||||
</div>
|
||||
<div class="item-arrow">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ArrowRight } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
// 定义列表数据
|
||||
const performanceList = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: "案件办理效率提升",
|
||||
description: "本月案件办理时间平均缩短20%,客户满意度显著提升",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Case+Efficiency",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "团队协作优化",
|
||||
description: "通过新的协作工具,团队沟通效率提升30%",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Team+Collab",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "客户反馈分析",
|
||||
description: "收集并分析了100份客户反馈,制定了改进计划",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Feedback",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "知识库更新",
|
||||
description: "新增50篇法律知识库文章,提升了团队专业能力",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Knowledge",
|
||||
},
|
||||
]);
|
||||
|
||||
// 点击事件处理
|
||||
function handleItemClick(item) {
|
||||
ElMessage.info(`您点击了:${item.title}`);
|
||||
// 这里可以添加跳转或其他逻辑
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.performance-list-container {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.performance-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
flex-shrink: 0;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20px;
|
||||
color: #c0c4cc;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
src/views/notice/index.vue
Normal file
138
src/views/notice/index.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="performance-list-container">
|
||||
<el-button type="primary" icon="edit" style="margin-bottom: 20px">新增公告</el-button>
|
||||
<div
|
||||
v-for="(item, index) in performanceList"
|
||||
:key="index"
|
||||
class="performance-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<div class="item-header">
|
||||
<img :src="item.imageUrl" :alt="item.title" class="item-image" />
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<h3 class="item-title">{{ item.title }}</h3>
|
||||
<p class="item-description">{{ item.description }}</p>
|
||||
</div>
|
||||
<div class="item-arrow">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ArrowRight } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
// 定义列表数据
|
||||
const performanceList = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: "案件办理效率提升",
|
||||
description: "本月案件办理时间平均缩短20%,客户满意度显著提升",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Case+Efficiency",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "团队协作优化",
|
||||
description: "通过新的协作工具,团队沟通效率提升30%",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Team+Collab",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "客户反馈分析",
|
||||
description: "收集并分析了100份客户反馈,制定了改进计划",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Feedback",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "知识库更新",
|
||||
description: "新增50篇法律知识库文章,提升了团队专业能力",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Knowledge",
|
||||
},
|
||||
]);
|
||||
|
||||
// 点击事件处理
|
||||
function handleItemClick(item) {
|
||||
ElMessage.info(`您点击了:${item.title}`);
|
||||
// 这里可以添加跳转或其他逻辑
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.performance-list-container {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.performance-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
flex-shrink: 0;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20px;
|
||||
color: #c0c4cc;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
src/views/performance/list/index.vue
Normal file
138
src/views/performance/list/index.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="performance-list-container">
|
||||
<el-button type="primary" icon="edit" style="margin-bottom: 20px">新增业绩</el-button>
|
||||
<div
|
||||
v-for="(item, index) in performanceList"
|
||||
:key="index"
|
||||
class="performance-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<div class="item-header">
|
||||
<img :src="item.imageUrl" :alt="item.title" class="item-image" />
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<h3 class="item-title">{{ item.title }}</h3>
|
||||
<p class="item-description">{{ item.description }}</p>
|
||||
</div>
|
||||
<div class="item-arrow">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ArrowRight } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
// 定义列表数据
|
||||
const performanceList = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: "案件办理效率提升",
|
||||
description: "本月案件办理时间平均缩短20%,客户满意度显著提升",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Case+Efficiency",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "团队协作优化",
|
||||
description: "通过新的协作工具,团队沟通效率提升30%",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Team+Collab",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "客户反馈分析",
|
||||
description: "收集并分析了100份客户反馈,制定了改进计划",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Feedback",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "知识库更新",
|
||||
description: "新增50篇法律知识库文章,提升了团队专业能力",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Knowledge",
|
||||
},
|
||||
]);
|
||||
|
||||
// 点击事件处理
|
||||
function handleItemClick(item) {
|
||||
ElMessage.info(`您点击了:${item.title}`);
|
||||
// 这里可以添加跳转或其他逻辑
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.performance-list-container {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.performance-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
flex-shrink: 0;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20px;
|
||||
color: #c0c4cc;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
src/views/registration/index.vue
Normal file
138
src/views/registration/index.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="performance-list-container">
|
||||
<el-button type="primary" icon="edit" style="margin-bottom: 20px">入库登记</el-button>
|
||||
<div
|
||||
v-for="(item, index) in performanceList"
|
||||
:key="index"
|
||||
class="performance-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<div class="item-header">
|
||||
<img :src="item.imageUrl" :alt="item.title" class="item-image" />
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<h3 class="item-title">{{ item.title }}</h3>
|
||||
<p class="item-description">{{ item.description }}</p>
|
||||
</div>
|
||||
<div class="item-arrow">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ArrowRight } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
// 定义列表数据
|
||||
const performanceList = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: "案件办理效率提升",
|
||||
description: "本月案件办理时间平均缩短20%,客户满意度显著提升",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Case+Efficiency",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "团队协作优化",
|
||||
description: "通过新的协作工具,团队沟通效率提升30%",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Team+Collab",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "客户反馈分析",
|
||||
description: "收集并分析了100份客户反馈,制定了改进计划",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Feedback",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "知识库更新",
|
||||
description: "新增50篇法律知识库文章,提升了团队专业能力",
|
||||
imageUrl: "https://via.placeholder.com/100x100?text=Knowledge",
|
||||
},
|
||||
]);
|
||||
|
||||
// 点击事件处理
|
||||
function handleItemClick(item) {
|
||||
ElMessage.info(`您点击了:${item.title}`);
|
||||
// 这里可以添加跳转或其他逻辑
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.performance-list-container {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.performance-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
flex-shrink: 0;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20px;
|
||||
color: #c0c4cc;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,26 +1,421 @@
|
||||
<template>
|
||||
<div class="stamp-application">
|
||||
<h1>申请用印页面</h1>
|
||||
<p>这是一个没有子节点的路由示例页面</p>
|
||||
<div class="pre-case-registration">
|
||||
<h1>申请用印</h1>
|
||||
|
||||
<!-- 预立案日期 -->
|
||||
<div class="form-item">
|
||||
<label class="form-label" for="preCaseDate">预立案日期*</label>
|
||||
<el-date-picker
|
||||
id="preCaseDate"
|
||||
v-model="formData.preCaseDate"
|
||||
type="date"
|
||||
placeholder="请选择预立案日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- 委托人信息 -->
|
||||
<div class="section">
|
||||
<h2>委托人信息</h2>
|
||||
<el-table
|
||||
:data="formData.clients"
|
||||
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-input v-model="scope.row.name" placeholder="请输入" style="width: 100%" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="idNumber" label="身份证号码/统一代码*" min-width="250">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.idNumber" placeholder="请输入" style="width: 100%" />
|
||||
</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 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>
|
||||
</div>
|
||||
<!-- 相对方信息 -->
|
||||
<div class="section">
|
||||
<h2>相对方信息</h2>
|
||||
<el-table
|
||||
:data="formData.opponents"
|
||||
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-input v-model="scope.row.name" placeholder="请输入" style="width: 100%" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="idNumber" label="身份证号码/统一代码*" min-width="250">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.idNumber" placeholder="请输入" style="width: 100%" />
|
||||
</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 class="table-actions">
|
||||
<el-button type="primary" @click="addOpponent">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增一项
|
||||
</el-button>
|
||||
<el-button type="danger" @click="batchDeleteOpponents">
|
||||
<el-icon><Delete /></el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 项目简述/案由 -->
|
||||
<div class="form-item">
|
||||
<label class="form-label" for="projectDescription">项目简述/案由*</label>
|
||||
<el-input
|
||||
id="projectDescription"
|
||||
v-model="formData.projectDescription"
|
||||
type="textarea"
|
||||
placeholder="简要陈述项目情况"
|
||||
:rows="4"
|
||||
style="width: 100%"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- 承办人员 -->
|
||||
<div class="form-item">
|
||||
<label class="form-label" for="handler">承办人员*</label>
|
||||
<el-select
|
||||
id="handler"
|
||||
v-model="formData.handler"
|
||||
placeholder="请选择"
|
||||
style="width: 100%"
|
||||
required
|
||||
>
|
||||
<!-- 这里可以根据实际情况动态加载承办人员列表 -->
|
||||
<el-option label="承办人1" value="1" />
|
||||
<el-option label="承办人2" value="2" />
|
||||
<el-option label="承办人3" value="3" />
|
||||
</el-select>
|
||||
</div>
|
||||
<!-- 提交按钮 -->
|
||||
<div class="form-actions">
|
||||
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||||
<el-button @click="handleSaveDraft">暂存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 可以在这里添加组件的逻辑
|
||||
import { ref, reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Plus, Delete } from "@element-plus/icons-vue";
|
||||
|
||||
// 定义表单数据类型
|
||||
interface Client {
|
||||
index: number;
|
||||
name: string;
|
||||
idNumber: string;
|
||||
}
|
||||
|
||||
interface Opponent {
|
||||
index: number;
|
||||
name: string;
|
||||
idNumber: string;
|
||||
}
|
||||
|
||||
interface FormData {
|
||||
preCaseDate: string;
|
||||
clients: Client[];
|
||||
opponents: Opponent[];
|
||||
projectDescription: string;
|
||||
handler: string;
|
||||
}
|
||||
|
||||
// 选择的委托人
|
||||
const selectedClients = ref<Client[]>([]);
|
||||
// 选择的相对方
|
||||
const selectedOpponents = ref<Opponent[]>([]);
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive<FormData>({
|
||||
preCaseDate: "",
|
||||
clients: [{ index: 1, name: "", idNumber: "" }],
|
||||
opponents: [{ index: 1, name: "", idNumber: "" }],
|
||||
projectDescription: "",
|
||||
handler: "",
|
||||
});
|
||||
|
||||
// 新增委托人
|
||||
const addClient = () => {
|
||||
const newIndex = formData.clients.length + 1;
|
||||
formData.clients.push({ index: newIndex, name: "", idNumber: "" });
|
||||
};
|
||||
|
||||
// 删除委托人
|
||||
const deleteClient = (index: number) => {
|
||||
if (formData.clients.length > 1) {
|
||||
formData.clients.splice(index, 1);
|
||||
// 更新序号
|
||||
formData.clients.forEach((client, idx) => {
|
||||
client.index = idx + 1;
|
||||
});
|
||||
} else if (formData.opponents.length === 0) {
|
||||
ElMessage.warning("委托方和相对方至少需要存在一个");
|
||||
} else {
|
||||
formData.clients.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// 复制委托人
|
||||
const copyClient = (client: Client) => {
|
||||
const newIndex = formData.clients.length + 1;
|
||||
formData.clients.push({ ...client, index: newIndex });
|
||||
};
|
||||
|
||||
// 处理委托人选择
|
||||
const handleClientSelectionChange = (selection: Client[]) => {
|
||||
selectedClients.value = selection;
|
||||
};
|
||||
|
||||
// 批量删除委托人
|
||||
const batchDeleteClients = () => {
|
||||
if (selectedClients.value.length === 0) {
|
||||
ElMessage.warning("请选择要删除的委托人");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否删除后还剩至少一个(或相对方存在)
|
||||
if (
|
||||
formData.clients.length - selectedClients.value.length === 0 &&
|
||||
formData.opponents.length === 0
|
||||
) {
|
||||
ElMessage.warning("委托方和相对方至少需要存在一个");
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行批量删除
|
||||
formData.clients = formData.clients.filter((client) => !selectedClients.value.includes(client));
|
||||
// 更新序号
|
||||
formData.clients.forEach((client, idx) => {
|
||||
client.index = idx + 1;
|
||||
});
|
||||
// 清空选择
|
||||
selectedClients.value = [];
|
||||
ElMessage.success("批量删除成功");
|
||||
};
|
||||
|
||||
// 新增相对方
|
||||
const addOpponent = () => {
|
||||
const newIndex = formData.opponents.length + 1;
|
||||
formData.opponents.push({ index: newIndex, name: "", idNumber: "" });
|
||||
};
|
||||
|
||||
// 删除相对方
|
||||
const deleteOpponent = (index: number) => {
|
||||
if (formData.opponents.length > 1) {
|
||||
formData.opponents.splice(index, 1);
|
||||
// 更新序号
|
||||
formData.opponents.forEach((opponent, idx) => {
|
||||
opponent.index = idx + 1;
|
||||
});
|
||||
} else if (formData.clients.length === 0) {
|
||||
ElMessage.warning("委托方和相对方至少需要存在一个");
|
||||
} else {
|
||||
formData.opponents.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// 复制相对方
|
||||
const copyOpponent = (opponent: Opponent) => {
|
||||
const newIndex = formData.opponents.length + 1;
|
||||
formData.opponents.push({ ...opponent, index: newIndex });
|
||||
};
|
||||
|
||||
// 处理相对方选择
|
||||
const handleOpponentSelectionChange = (selection: Opponent[]) => {
|
||||
selectedOpponents.value = selection;
|
||||
};
|
||||
|
||||
// 批量删除相对方
|
||||
const batchDeleteOpponents = () => {
|
||||
if (selectedOpponents.value.length === 0) {
|
||||
ElMessage.warning("请选择要删除的相对方");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否删除后还剩至少一个(或委托方存在)
|
||||
if (
|
||||
formData.opponents.length - selectedOpponents.value.length === 0 &&
|
||||
formData.clients.length === 0
|
||||
) {
|
||||
ElMessage.warning("委托方和相对方至少需要存在一个");
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行批量删除
|
||||
formData.opponents = formData.opponents.filter(
|
||||
(opponent) => !selectedOpponents.value.includes(opponent)
|
||||
);
|
||||
// 更新序号
|
||||
formData.opponents.forEach((opponent, idx) => {
|
||||
opponent.index = idx + 1;
|
||||
});
|
||||
// 清空选择
|
||||
selectedOpponents.value = [];
|
||||
ElMessage.success("批量删除成功");
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = () => {
|
||||
// 表单验证
|
||||
if (!formData.preCaseDate) {
|
||||
ElMessage.error("请选择预立案日期");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证委托方和相对方至少存在一个
|
||||
if (formData.clients.length === 0 && formData.opponents.length === 0) {
|
||||
ElMessage.error("委托方和相对方至少需要存在一个");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证委托人信息(如果存在)
|
||||
const invalidClients = formData.clients.filter((client) => !client.name || !client.idNumber);
|
||||
if (invalidClients.length > 0) {
|
||||
ElMessage.error("请填写完整的委托人信息");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证相对方信息(如果存在)
|
||||
const invalidOpponents = formData.opponents.filter(
|
||||
(opponent) => !opponent.name || !opponent.idNumber
|
||||
);
|
||||
if (invalidOpponents.length > 0) {
|
||||
ElMessage.error("请填写完整的相对方信息");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!formData.projectDescription) {
|
||||
ElMessage.error("请填写项目简述/案由");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!formData.handler) {
|
||||
ElMessage.error("请选择承办人员");
|
||||
return;
|
||||
}
|
||||
|
||||
// 提交数据到后端
|
||||
console.log("提交表单数据:", formData);
|
||||
ElMessage.success("表单提交成功");
|
||||
};
|
||||
|
||||
// 暂存表单
|
||||
const handleSaveDraft = () => {
|
||||
// 保存草稿逻辑
|
||||
console.log("暂存表单数据:", formData);
|
||||
ElMessage.success("表单暂存成功");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stamp-application {
|
||||
.pre-case-registration {
|
||||
max-width: 1000px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
font-size: 16px;
|
||||
.section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
font-size: 18px;
|
||||
margin-bottom: 15px;
|
||||
color: #606266;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
/* 适配不同屏幕尺寸 */
|
||||
@media (max-width: 768px) {
|
||||
.pre-case-registration {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { type ConfigEnv, type UserConfig, loadEnv, defineConfig, PluginOption } from "vite";
|
||||
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";
|
||||
@@ -20,11 +20,12 @@ const __APP_INFO__ = {
|
||||
const pathSrc = resolve(__dirname, "src");
|
||||
|
||||
// Vite配置 https://cn.vitejs.dev/config
|
||||
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
export default defineConfig(({ mode }: ConfigEnv) => {
|
||||
const env = loadEnv(mode, process.cwd());
|
||||
const isProduction = mode === "production";
|
||||
|
||||
return {
|
||||
base: "./", // 设置为相对路径,支持直接打开index.html
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": pathSrc,
|
||||
@@ -40,15 +41,16 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
},
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
port: +env.VITE_APP_PORT,
|
||||
port: +(env.VITE_APP_PORT as string),
|
||||
open: true,
|
||||
proxy: {
|
||||
// 代理 /dev-api 的请求
|
||||
[env.VITE_APP_BASE_API]: {
|
||||
[env.VITE_APP_BASE_API as string]: {
|
||||
changeOrigin: true,
|
||||
// 代理目标地址:https://api.youlai.tech
|
||||
target: env.VITE_APP_API_URL,
|
||||
rewrite: (path: string) => path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
|
||||
target: env.VITE_APP_API_URL as string,
|
||||
rewrite: (path: string) =>
|
||||
path.replace(new RegExp("^" + (env.VITE_APP_BASE_API as string)), ""),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -86,7 +88,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
dts: false,
|
||||
// dts: "src/types/components.d.ts",
|
||||
}),
|
||||
] as PluginOption[],
|
||||
],
|
||||
// 预加载项目必需的组件
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
@@ -192,7 +194,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
// 构建配置
|
||||
build: {
|
||||
chunkSizeWarningLimit: 2000, // 消除打包大小超过500kb警告
|
||||
minify: isProduction ? "terser" : false, // 只在生产环境启用压缩
|
||||
minify: isProduction ? ("terser" as const) : false, // 只在生产环境启用压缩
|
||||
terserOptions: isProduction
|
||||
? {
|
||||
compress: {
|
||||
|
||||
Reference in New Issue
Block a user