Merge branch 'dev' into dev-lgw
This commit is contained in:
4
ruoyi-ui/.gitignore
vendored
4
ruoyi-ui/.gitignore
vendored
@@ -21,3 +21,7 @@ selenium-debug.log
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# 备份文件
|
||||
*.backup
|
||||
*.bak
|
||||
|
||||
40
ruoyi-ui/src/api/ccdi/modelParam.js
Normal file
40
ruoyi-ui/src/api/ccdi/modelParam.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 查询模型列表
|
||||
* @param {Object} query - 查询参数
|
||||
* @param {Number} query.projectId - 项目ID
|
||||
*/
|
||||
export function listModels(query) {
|
||||
return request({
|
||||
url: '/ccdi/modelParam/modelList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询模型参数列表
|
||||
* @param {Object} query - 查询参数
|
||||
* @param {Number} query.projectId - 项目ID
|
||||
* @param {String} query.modelCode - 模型编码
|
||||
*/
|
||||
export function listParams(query) {
|
||||
return request({
|
||||
url: '/ccdi/modelParam/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存模型参数
|
||||
* @param {Object} data - 保存数据
|
||||
*/
|
||||
export function saveParams(data) {
|
||||
return request({
|
||||
url: '/ccdi/modelParam/save',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询初核项目列表
|
||||
// 创建初核项目
|
||||
export function createProject(data) {
|
||||
return request({
|
||||
url: '/ccdi/project',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 查询初核项目列表(分页)
|
||||
export function listProject(query) {
|
||||
return request({
|
||||
url: '/ccdi/project/list',
|
||||
@@ -86,7 +95,7 @@ export function importFromHistory(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// Mock数据:获取项目列表
|
||||
// Mock数据:获取项目列表(保留用于测试)
|
||||
export function getMockProjectList() {
|
||||
return Promise.resolve({
|
||||
code: 200,
|
||||
@@ -95,35 +104,44 @@ export function getMockProjectList() {
|
||||
{
|
||||
projectId: 1,
|
||||
projectName: '2024年Q1初核',
|
||||
projectDesc: '2024年第一季度纪检初核排查工作',
|
||||
description: '2024年第一季度纪检初核排查工作',
|
||||
createTime: '2024-01-01',
|
||||
projectStatus: '0',
|
||||
status: '0',
|
||||
configType: 'default',
|
||||
targetCount: 500,
|
||||
warningCount: 15,
|
||||
startDate: '2024-01-01',
|
||||
endDate: '2024-03-31'
|
||||
highRiskCount: 5,
|
||||
mediumRiskCount: 10,
|
||||
lowRiskCount: 0,
|
||||
createBy: 'admin',
|
||||
createByName: '管理员'
|
||||
},
|
||||
{
|
||||
projectId: 2,
|
||||
projectName: '2023年Q4初核',
|
||||
projectDesc: '2023年第四季度纪检初核排查工作',
|
||||
description: '2023年第四季度纪检初核排查工作',
|
||||
createTime: '2023-10-01',
|
||||
projectStatus: '1',
|
||||
status: '1',
|
||||
configType: 'custom',
|
||||
targetCount: 480,
|
||||
warningCount: 23,
|
||||
startDate: '2023-10-01',
|
||||
endDate: '2023-12-31'
|
||||
highRiskCount: 8,
|
||||
mediumRiskCount: 15,
|
||||
lowRiskCount: 0,
|
||||
createBy: 'admin',
|
||||
createByName: '管理员'
|
||||
},
|
||||
{
|
||||
projectId: 3,
|
||||
projectName: '2023年Q3初核',
|
||||
projectDesc: '2023年第三季度纪检初核排查工作',
|
||||
description: '2023年第三季度纪检初核排查工作',
|
||||
createTime: '2023-07-01',
|
||||
projectStatus: '2',
|
||||
status: '2',
|
||||
configType: 'default',
|
||||
targetCount: 450,
|
||||
warningCount: 18,
|
||||
startDate: '2023-07-01',
|
||||
endDate: '2023-09-30'
|
||||
highRiskCount: 0,
|
||||
mediumRiskCount: 18,
|
||||
lowRiskCount: 5,
|
||||
createBy: 'admin',
|
||||
createByName: '管理员'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -137,21 +155,29 @@ export function getMockHistoryProjects() {
|
||||
{
|
||||
projectId: 3,
|
||||
projectName: '2023年Q3初核',
|
||||
projectDesc: '2023年第三季度纪检初核排查工作',
|
||||
description: '2023年第三季度纪检初核排查工作',
|
||||
createTime: '2023-07-01',
|
||||
projectStatus: '2',
|
||||
status: '2',
|
||||
targetCount: 450,
|
||||
warningCount: 18
|
||||
},
|
||||
{
|
||||
projectId: 4,
|
||||
projectName: '2023年Q2初核',
|
||||
projectDesc: '2023年第二季度纪检初核排查工作',
|
||||
description: '2023年第二季度纪检初核排查工作',
|
||||
createTime: '2023-04-01',
|
||||
projectStatus: '2',
|
||||
status: '2',
|
||||
targetCount: 420,
|
||||
warningCount: 12
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
// 查询项目状态统计
|
||||
export function getStatusCounts() {
|
||||
return request({
|
||||
url: '/ccdi/project/statusCounts',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
194
ruoyi-ui/src/views/ccdi/modelParam/index.vue
Normal file
194
ruoyi-ui/src/views/ccdi/modelParam/index.vue
Normal file
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 顶部标题 -->
|
||||
<div class="header">
|
||||
<span class="title">模型参数管理</span>
|
||||
</div>
|
||||
|
||||
<!-- 查询筛选区 -->
|
||||
<div class="filter-container">
|
||||
<el-form :inline="true" :model="queryParams" ref="queryForm">
|
||||
<el-form-item label="模型名称" prop="modelCode">
|
||||
<el-select v-model="queryParams.modelCode" placeholder="请选择模型">
|
||||
<el-option
|
||||
v-for="model in modelList"
|
||||
:key="model.modelCode"
|
||||
:label="model.modelName"
|
||||
:value="model.modelCode"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">
|
||||
查询
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 参数配置表格 -->
|
||||
<div class="table-container">
|
||||
<h3 class="table-title">阈值参数配置</h3>
|
||||
<el-table :data="paramList" border style="width: 100%">
|
||||
<el-table-column label="监测项" prop="paramName" width="200" />
|
||||
<el-table-column label="描述" prop="paramDesc" />
|
||||
<el-table-column label="阈值设置" width="200">
|
||||
<template #default="{ row }">
|
||||
<el-input
|
||||
v-model="row.paramValue"
|
||||
placeholder="请输入阈值"
|
||||
@input="markAsModified(row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" prop="paramUnit" width="120" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="button-container">
|
||||
<el-button type="primary" @click="handleSave" :loading="saving">
|
||||
保存配置
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listModels, listParams, saveParams} from "@/api/ccdi/modelParam";
|
||||
|
||||
export default {
|
||||
name: "ModelParam",
|
||||
data() {
|
||||
return {
|
||||
// 模型列表
|
||||
modelList: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
modelCode: undefined,
|
||||
projectId: 0, // 默认查询系统级参数
|
||||
},
|
||||
// 参数列表
|
||||
paramList: [],
|
||||
// 保存中状态
|
||||
saving: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getModelList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询模型列表 */
|
||||
getModelList() {
|
||||
listModels({ projectId: this.queryParams.projectId }).then((response) => {
|
||||
this.modelList = response.data;
|
||||
if (this.modelList.length > 0) {
|
||||
this.queryParams.modelCode = this.modelList[0].modelCode;
|
||||
this.handleQuery();
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 查询参数列表 */
|
||||
handleQuery() {
|
||||
if (!this.queryParams.modelCode) {
|
||||
this.$message.warning("请选择模型");
|
||||
return;
|
||||
}
|
||||
listParams(this.queryParams).then((response) => {
|
||||
this.paramList = response.data;
|
||||
});
|
||||
},
|
||||
/** 标记参数为已修改 */
|
||||
markAsModified(row) {
|
||||
row.modified = true;
|
||||
},
|
||||
/** 保存配置 */
|
||||
handleSave() {
|
||||
if (!this.queryParams.modelCode) {
|
||||
this.$message.warning("请选择模型");
|
||||
return;
|
||||
}
|
||||
|
||||
// 只保存修改过的参数值
|
||||
const modifiedParams = this.paramList.filter((item) => item.modified);
|
||||
if (modifiedParams.length === 0) {
|
||||
this.$message.info("没有需要保存的修改");
|
||||
return;
|
||||
}
|
||||
|
||||
const saveDTO = {
|
||||
projectId: this.queryParams.projectId,
|
||||
modelCode: this.queryParams.modelCode,
|
||||
params: modifiedParams.map((item) => ({
|
||||
paramCode: item.paramCode,
|
||||
paramValue: item.paramValue,
|
||||
})),
|
||||
};
|
||||
|
||||
this.saving = true;
|
||||
saveParams(saveDTO)
|
||||
.then((response) => {
|
||||
this.$modal.msgSuccess("保存成功");
|
||||
// 清除修改标记
|
||||
this.paramList.forEach((item) => {
|
||||
item.modified = false;
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.saving = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin: 0 0 15px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
@@ -73,7 +73,7 @@
|
||||
>
|
||||
{{ isUploading ? '导入中...' : '开始导入' }}
|
||||
</el-button>
|
||||
<el-button icon="el-icon-close" @click="visible = false" :disabled="isUploading">
|
||||
<el-button :disabled="isUploading" icon="el-icon-close" @click="handleCancel">
|
||||
取 消
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -144,6 +144,10 @@ export default {
|
||||
this.isFileSelected = false;
|
||||
this.$emit("close");
|
||||
},
|
||||
handleCancel() {
|
||||
// 通过 $emit 通知父组件更新 visible 状态,而不是直接修改 prop
|
||||
this.$emit('update:visible', false);
|
||||
},
|
||||
handleImportTypeChange() {
|
||||
if (this.$refs.upload) {
|
||||
this.$refs.upload.clearFiles();
|
||||
|
||||
@@ -19,116 +19,44 @@
|
||||
<el-input
|
||||
v-model="formData.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
maxlength="50"
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 项目描述 -->
|
||||
<el-form-item label="项目描述" prop="projectDesc">
|
||||
<el-form-item label="项目描述" prop="description">
|
||||
<el-input
|
||||
v-model="formData.projectDesc"
|
||||
v-model="formData.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
:rows="4"
|
||||
placeholder="请输入项目描述"
|
||||
maxlength="200"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 目标人员 -->
|
||||
<el-form-item label="目标人员">
|
||||
<div class="target-persons-wrapper">
|
||||
<el-button
|
||||
icon="el-icon-plus"
|
||||
size="small"
|
||||
@click="handleAddPerson"
|
||||
>添加人员</el-button>
|
||||
<div v-if="formData.targetPersons && formData.targetPersons.length > 0" class="persons-list">
|
||||
<el-tag
|
||||
v-for="(person, index) in formData.targetPersons"
|
||||
:key="index"
|
||||
closable
|
||||
@close="handleRemovePerson(index)"
|
||||
type="info"
|
||||
>
|
||||
{{ person.name }} ({{ person.certNo }})
|
||||
</el-tag>
|
||||
</div>
|
||||
<div v-else class="empty-hint">
|
||||
<i class="el-icon-info"></i>
|
||||
<span>暂未添加目标人员,可后续添加</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 时间范围 -->
|
||||
<el-form-item label="开始日期" prop="startDate">
|
||||
<el-date-picker
|
||||
v-model="formData.startDate"
|
||||
type="date"
|
||||
placeholder="选择开始日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="结束日期" prop="endDate">
|
||||
<el-date-picker
|
||||
v-model="formData.endDate"
|
||||
type="date"
|
||||
placeholder="选择结束日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
:picker-options="endDatePickerOptions"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 目标人数 -->
|
||||
<el-form-item label="目标人数" prop="targetCount">
|
||||
<el-input-number
|
||||
v-model="formData.targetCount"
|
||||
:min="0"
|
||||
:max="10000"
|
||||
:step="10"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<!-- 配置方式 -->
|
||||
<el-form-item label="配置方式" prop="configType">
|
||||
<el-radio-group v-model="formData.configType">
|
||||
<el-radio label="default">全局默认模型参数配置</el-radio>
|
||||
<el-radio label="custom">自定义项目规则参数配置</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 高级设置(可选扩展) -->
|
||||
<el-collapse class="advanced-settings" v-model="activeCollapse">
|
||||
<el-collapse-item title="高级设置" name="advanced">
|
||||
<el-form label-width="100px" label-position="right">
|
||||
<el-form-item label="自动预警">
|
||||
<el-switch v-model="formData.autoWarning" />
|
||||
<span class="form-item-hint">开启后将自动计算预警人员</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="预警阈值">
|
||||
<el-input-number
|
||||
v-model="formData.warningThreshold"
|
||||
:min="1"
|
||||
:max="100"
|
||||
controls-position="right"
|
||||
/>
|
||||
<span class="form-item-hint">匹配度低于此值时触发预警</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">
|
||||
<i v-if="!submitting" class="el-icon-check"></i>
|
||||
确 定
|
||||
创建项目
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createProject } from '@/api/ccdiProject'
|
||||
|
||||
export default {
|
||||
name: 'AddProjectDialog',
|
||||
props: {
|
||||
@@ -146,52 +74,21 @@ export default {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
// 结束日期验证规则
|
||||
const validateEndDate = (rule, value, callback) => {
|
||||
if (value && this.formData.startDate && value < this.formData.startDate) {
|
||||
callback(new Error('结束日期不能早于开始日期'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
submitting: false,
|
||||
activeCollapse: [],
|
||||
formData: {
|
||||
projectId: null,
|
||||
projectName: '',
|
||||
projectDesc: '',
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
targetCount: 0,
|
||||
targetPersons: [],
|
||||
autoWarning: true,
|
||||
warningThreshold: 60
|
||||
description: '',
|
||||
configType: 'default'
|
||||
},
|
||||
rules: {
|
||||
projectName: [
|
||||
{ required: true, message: '请输入项目名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
startDate: [
|
||||
{ required: true, message: '请选择开始日期', trigger: 'change' }
|
||||
],
|
||||
endDate: [
|
||||
{ required: true, message: '请选择结束日期', trigger: 'change' },
|
||||
{ validator: validateEndDate, trigger: 'change' }
|
||||
],
|
||||
targetCount: [
|
||||
{ required: true, message: '请输入目标人数', trigger: 'blur' }
|
||||
configType: [
|
||||
{ required: true, message: '请选择配置方式', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
endDatePickerOptions: {
|
||||
disabledDate: (time) => {
|
||||
if (this.formData.startDate) {
|
||||
return time.getTime() < new Date(this.formData.startDate).getTime()
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -219,7 +116,6 @@ export default {
|
||||
},
|
||||
visible(val) {
|
||||
if (val) {
|
||||
// 对话框打开时重置表单验证状态
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.projectForm) {
|
||||
this.$refs.projectForm.clearValidate()
|
||||
@@ -229,100 +125,38 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 添加人员 */
|
||||
handleAddPerson() {
|
||||
// 这里可以打开一个选择人员的对话框
|
||||
this.$message.info('人员选择功能待实现')
|
||||
// 模拟添加人员
|
||||
if (!this.formData.targetPersons) {
|
||||
this.formData.targetPersons = []
|
||||
}
|
||||
this.formData.targetPersons.push({
|
||||
name: '张三',
|
||||
certNo: '3301**********202101'
|
||||
})
|
||||
},
|
||||
/** 移除人员 */
|
||||
handleRemovePerson(index) {
|
||||
this.formData.targetPersons.splice(index, 1)
|
||||
},
|
||||
/** 提交表单 */
|
||||
handleSubmit() {
|
||||
this.$refs.projectForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.submitting = true
|
||||
// 模拟提交
|
||||
setTimeout(() => {
|
||||
createProject(this.formData).then(response => {
|
||||
this.$message.success('项目创建成功')
|
||||
this.submitting = false
|
||||
this.$emit('submit', { ...this.formData })
|
||||
}, 500)
|
||||
this.$emit('submit', response.data)
|
||||
this.handleClose()
|
||||
}).catch(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 关闭对话框 */
|
||||
handleClose() {
|
||||
this.$emit('close')
|
||||
this.$refs.projectForm.resetFields()
|
||||
this.formData = {
|
||||
projectId: null,
|
||||
projectName: '',
|
||||
projectDesc: '',
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
targetCount: 0,
|
||||
targetPersons: [],
|
||||
autoWarning: true,
|
||||
warningThreshold: 60
|
||||
description: '',
|
||||
configType: 'default'
|
||||
}
|
||||
this.activeCollapse = []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.target-persons-wrapper {
|
||||
width: 100%;
|
||||
|
||||
.persons-list {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
margin-top: 12px;
|
||||
padding: 12px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-settings {
|
||||
margin: 20px 0;
|
||||
|
||||
:deep(.el-collapse-item__header) {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.form-item-hint {
|
||||
margin-left: 12px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
|
||||
@@ -330,4 +164,14 @@ export default {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-radio-group) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
.el-radio {
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,173 +1,182 @@
|
||||
<template>
|
||||
<div class="project-table-container">
|
||||
<el-card class="table-card" shadow="hover">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="dataList"
|
||||
style="width: 100%"
|
||||
:header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: '600' }"
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="dataList"
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- 项目名称(含描述) -->
|
||||
<el-table-column
|
||||
label="项目名称"
|
||||
min-width="180"
|
||||
align="left"
|
||||
>
|
||||
<!-- 序号 -->
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="60"
|
||||
align="center"
|
||||
/>
|
||||
<template slot-scope="scope">
|
||||
<div class="project-info-cell">
|
||||
<div class="project-name">{{ scope.row.projectName }}</div>
|
||||
<div class="project-desc">{{ scope.row.description || '暂无描述' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 项目名称 -->
|
||||
<el-table-column
|
||||
label="项目名称"
|
||||
min-width="160"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<div class="project-name-cell">
|
||||
<div class="name">{{ scope.row.projectName }}</div>
|
||||
<div class="desc">{{ scope.row.projectDesc }}</div>
|
||||
<!-- 更新/创建时间 -->
|
||||
<el-table-column
|
||||
prop="updateTime"
|
||||
label="更新/创建时间"
|
||||
width="180"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.updateTime || scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 创建人 -->
|
||||
<el-table-column
|
||||
prop="createByName"
|
||||
label="创建人"
|
||||
width="120"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 状态 -->
|
||||
<el-table-column
|
||||
prop="status"
|
||||
label="状态"
|
||||
width="120"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<div class="status-tag">
|
||||
<span class="status-dot" :style="{ color: getStatusColor(scope.row.status) }">●</span>
|
||||
<dict-tag :options="dict.type.ccdi_project_status" :value="scope.row.status"/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 目标人数 -->
|
||||
<el-table-column
|
||||
prop="targetCount"
|
||||
label="目标人数"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 预警人数(带悬停详情) -->
|
||||
<el-table-column
|
||||
label="预警人数"
|
||||
width="120"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<div slot="content">
|
||||
<div style="padding: 8px;">
|
||||
<div style="margin-bottom: 8px; font-weight: bold; color: #303133;">
|
||||
风险人数统计
|
||||
</div>
|
||||
<div style="margin-bottom: 6px;">
|
||||
<span style="color: #f56c6c;">● 高风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.highRiskCount }} 人</span>
|
||||
</div>
|
||||
<div style="margin-bottom: 6px;">
|
||||
<span style="color: #e6a23c;">● 中风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.mediumRiskCount }} 人</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #909399;">● 低风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.lowRiskCount }} 人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 创建时间 -->
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
prop="createTime"
|
||||
width="110"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 状态 -->
|
||||
<el-table-column
|
||||
label="状态"
|
||||
prop="projectStatus"
|
||||
width="90"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-tag
|
||||
:type="getStatusType(scope.row.projectStatus)"
|
||||
size="medium"
|
||||
effect="plain"
|
||||
>
|
||||
{{ getStatusLabel(scope.row.projectStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 目标人数 -->
|
||||
<el-table-column
|
||||
label="目标人数"
|
||||
prop="targetCount"
|
||||
width="80"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span class="count-number">{{ scope.row.targetCount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 预警人数 -->
|
||||
<el-table-column
|
||||
label="预警人数"
|
||||
width="90"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span :class="getWarningClass(scope.row)">{{ scope.row.warningCount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作 -->
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="200"
|
||||
align="center"
|
||||
fixed="right"
|
||||
class-name="operation-column"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<div class="operation-buttons">
|
||||
<!-- 进行中项目 -->
|
||||
<template v-if="scope.row.projectStatus === '0'">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-s-data"
|
||||
@click="handleEnter(scope.row)"
|
||||
>进入项目</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@click="handleReAnalyze(scope.row)"
|
||||
>重新分析</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 已完成项目 -->
|
||||
<template v-else-if="scope.row.projectStatus === '1'">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleViewResult(scope.row)"
|
||||
>查看结果</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@click="handleReAnalyze(scope.row)"
|
||||
>重新分析</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-folder"
|
||||
@click="handleArchive(scope.row)"
|
||||
>归档</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 已归档项目 -->
|
||||
<template v-else>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-document"
|
||||
@click="handleDetail(scope.row)"
|
||||
>查看详情</el-button>
|
||||
</template>
|
||||
<div class="warning-count-wrapper">
|
||||
<span :class="getWarningClass(scope.row)" style="cursor: pointer;">
|
||||
{{ scope.row.highRiskCount + scope.row.mediumRiskCount + scope.row.lowRiskCount }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
:current-page="pageParams.pageNum"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
:page-size="pageParams.pageSize"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 操作列 -->
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="350"
|
||||
align="left"
|
||||
fixed="right"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<!-- 进行中状态 (status = '0') -->
|
||||
<el-button
|
||||
v-if="scope.row.status === '0'"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-right"
|
||||
@click="handleEnter(scope.row)"
|
||||
>进入项目</el-button>
|
||||
|
||||
<!-- 已完成状态 (status = '1') -->
|
||||
<template v-if="scope.row.status === '1'">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleViewResult(scope.row)"
|
||||
>查看结果</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-refresh"
|
||||
@click="handleReAnalyze(scope.row)"
|
||||
>重新分析</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-folder"
|
||||
@click="handleArchive(scope.row)"
|
||||
>归档</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 已归档状态 (status = '2') -->
|
||||
<el-button
|
||||
v-if="scope.row.status === '2'"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleViewResult(scope.row)"
|
||||
>查看结果</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-show="total > 0"
|
||||
:current-page="pageParams.pageNum"
|
||||
:page-size="pageParams.pageSize"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
style="margin-top: 16px; text-align: right;"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ProjectTable',
|
||||
dicts: ['ccdi_project_status', 'ccdi_config_type'],
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -181,57 +190,49 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 获取状态类型 */
|
||||
getStatusType(status) {
|
||||
const statusMap = {
|
||||
'0': 'primary', // 进行中
|
||||
'1': 'success', // 已完成
|
||||
'2': 'info' // 已归档
|
||||
getStatusColor(status) {
|
||||
const colorMap = {
|
||||
'0': '#1890ff', // 进行中 - 蓝色
|
||||
'1': '#52c41a', // 已完成 - 绿色
|
||||
'2': '#8c8c8c' // 已归档 - 灰色
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
return colorMap[status] || '#8c8c8c'
|
||||
},
|
||||
/** 获取状态标签 */
|
||||
getStatusLabel(status) {
|
||||
const statusMap = {
|
||||
'0': '进行中',
|
||||
'1': '已完成',
|
||||
'2': '已归档'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
},
|
||||
/** 获取预警数量样式类名 */
|
||||
|
||||
getWarningClass(row) {
|
||||
if (row.warningCount > 20) return 'warning-high'
|
||||
if (row.warningCount > 10) return 'warning-medium'
|
||||
return 'warning-normal'
|
||||
const total = row.highRiskCount + row.mediumRiskCount + row.lowRiskCount
|
||||
if (row.highRiskCount > 0) {
|
||||
return 'text-danger text-bold'
|
||||
} else if (row.mediumRiskCount > 0) {
|
||||
return 'text-warning text-bold'
|
||||
} else if (total > 0) {
|
||||
return 'text-info'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
/** 进入项目 */
|
||||
|
||||
handleEnter(row) {
|
||||
this.$emit('enter', row)
|
||||
},
|
||||
/** 查看详情 */
|
||||
handleDetail(row) {
|
||||
this.$emit('detail', row)
|
||||
},
|
||||
/** 查看结果 */
|
||||
|
||||
handleViewResult(row) {
|
||||
this.$emit('view-result', row)
|
||||
},
|
||||
/** 重新分析 */
|
||||
|
||||
handleReAnalyze(row) {
|
||||
this.$emit('re-analyze', row)
|
||||
},
|
||||
/** 归档 */
|
||||
|
||||
handleArchive(row) {
|
||||
this.$emit('archive', row)
|
||||
},
|
||||
/** 分页大小变化 */
|
||||
|
||||
handleSizeChange(val) {
|
||||
this.$emit('pagination', { pageSize: val, pageNum: 1 })
|
||||
this.$emit('pagination', { pageNum: this.pageParams.pageNum, pageSize: val })
|
||||
},
|
||||
/** 当前页变化 */
|
||||
|
||||
handleCurrentChange(val) {
|
||||
this.$emit('pagination', { pageNum: val })
|
||||
this.$emit('pagination', { pageNum: val, pageSize: this.pageParams.pageSize })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,115 +240,172 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.project-table-container {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
margin-top: 16px;
|
||||
|
||||
.table-card {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
// 表格整体样式 - 扁平化设计
|
||||
::v-deep .el-table {
|
||||
// 移除边框和卡片效果,设置透明背景
|
||||
border: none !important;
|
||||
background-color: transparent !important;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
// 表头样式 - 扁平化,无背景色
|
||||
th.el-table__cell {
|
||||
background-color: transparent !important;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
height: 44px;
|
||||
padding: 12px 10px;
|
||||
|
||||
.project-name-cell {
|
||||
.name {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 2px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.count-number {
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.warning-count-cell {
|
||||
.warning-high {
|
||||
color: #F56C6C;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.warning-medium {
|
||||
color: #E6A23C;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.warning-normal {
|
||||
color: #67C23A;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
border-top: 1px solid #EBEEF5;
|
||||
}
|
||||
|
||||
// 表格行样式优化
|
||||
:deep(.el-table) {
|
||||
.el-table__row {
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
// 只保留底部一条分隔线
|
||||
border-bottom: 2px solid #e0e0e0 !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #dcdfe6;
|
||||
border-radius: 3px;
|
||||
// 数据行样式 - 增加留白,移除分隔线
|
||||
td.el-table__cell {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
height: 48px;
|
||||
padding: 12px 10px;
|
||||
border-bottom: none !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #c0c4cc;
|
||||
// 移除列分隔线
|
||||
.el-table__body-wrapper {
|
||||
.cell {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 操作列样式
|
||||
.operation-column {
|
||||
.cell {
|
||||
padding: 0 8px;
|
||||
// 悬停效果
|
||||
.el-table__row {
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&:hover > td.el-table__cell {
|
||||
background-color: #fafafa !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除额外边框
|
||||
&::before,
|
||||
&::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 移除 inner border
|
||||
.el-table__inner-wrapper::before {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.operation-buttons {
|
||||
display: flex;
|
||||
.status-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
gap: 6px;
|
||||
|
||||
:deep(.el-button--mini) {
|
||||
padding: 4px 6px;
|
||||
.status-dot {
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.project-info-cell {
|
||||
padding: 4px 0;
|
||||
line-height: 1.4;
|
||||
|
||||
.project-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 2px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.project-desc {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-count-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.text-info {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// 操作按钮样式 - Material Design 风格
|
||||
::v-deep .el-button--text {
|
||||
color: #1890ff;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #096dd9;
|
||||
background-color: rgba(24, 144, 255, 0.08);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:deep(.el-button--mini .el-icon--left) {
|
||||
margin-right: 2px;
|
||||
&:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
:deep(.el-button + .el-button) {
|
||||
margin-left: 0;
|
||||
// 按钮间距
|
||||
& + .el-button--text {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
// 分页样式优化 - Material Design 风格
|
||||
::v-deep .el-pagination {
|
||||
margin-top: 24px;
|
||||
text-align: right;
|
||||
|
||||
// 扁平化按钮
|
||||
.btn-prev,
|
||||
.btn-next,
|
||||
.el-pager li {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pager li.active {
|
||||
background-color: #1890ff;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.el-pagination__total,
|
||||
.el-pagination__sizes,
|
||||
.el-pagination__jump {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="quick-entry-container">
|
||||
<div class="section-title">
|
||||
<i class="el-icon-s-grid title-icon"></i>
|
||||
<span>快捷入口</span>
|
||||
<span>快捷方式</span>
|
||||
</div>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="6">
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">导入历史项目</div>
|
||||
<div class="card-desc">从历史项目中快速创建新项目</div>
|
||||
<div class="card-desc">从历史项目中导入配置</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@@ -23,7 +23,7 @@
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">创建季度初核</div>
|
||||
<div class="card-desc">按季度创建初核排查项目</div>
|
||||
<div class="card-desc">创建季度初核</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@@ -34,7 +34,7 @@
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">创建新员工排查</div>
|
||||
<div class="card-desc">针对新入职员工的初核排查</div>
|
||||
<div class="card-desc">创建新员工排查</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">创建高风险专项</div>
|
||||
<div class="card-desc">针对高风险人员的专项排查</div>
|
||||
<div class="card-desc">创建高风险专项</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@@ -123,7 +123,7 @@ export default {
|
||||
.card-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -134,19 +134,19 @@ export default {
|
||||
color: white;
|
||||
|
||||
&.import-icon {
|
||||
background-color: #667eea;
|
||||
background-color: #6B7280;
|
||||
}
|
||||
|
||||
&.quarterly-icon {
|
||||
background-color: #f5576c;
|
||||
background-color: #3B82F6;
|
||||
}
|
||||
|
||||
&.employee-icon {
|
||||
background-color: #4facfe;
|
||||
background-color: #10B981;
|
||||
}
|
||||
|
||||
&.highrisk-icon {
|
||||
background-color: #F56C6C;
|
||||
background-color: #F59E0B;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,55 +1,27 @@
|
||||
<template>
|
||||
<div class="search-bar-container">
|
||||
<el-card class="search-card" shadow="hover">
|
||||
<el-row :gutter="12" align="middle">
|
||||
<el-col :span="8">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入项目名称"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
size="medium"
|
||||
@keyup.enter.native="handleSearch"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="handleSearch"
|
||||
>搜索</el-button>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-select
|
||||
v-model="selectedStatus"
|
||||
placeholder="项目状态"
|
||||
clearable
|
||||
size="medium"
|
||||
style="width: 100%"
|
||||
@change="handleStatusChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="11" style="text-align: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
size="medium"
|
||||
@click="handleAdd"
|
||||
>新建项目</el-button>
|
||||
<el-button
|
||||
icon="el-icon-folder-opened"
|
||||
size="medium"
|
||||
@click="handleImport"
|
||||
>导入历史项目</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
<div class="search-filter-bar">
|
||||
<div class="search-input-wrapper">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入关键词搜索项目"
|
||||
clearable
|
||||
size="small"
|
||||
class="search-input"
|
||||
@keyup.enter.native="handleSearch"
|
||||
@clear="handleSearch"
|
||||
/>
|
||||
<el-button type="primary" size="small" @click="handleSearch">搜索</el-button>
|
||||
</div>
|
||||
<div class="tab-filters">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
:key="tab.value"
|
||||
:class="['tab-item', { active: activeTab === tab.value }]"
|
||||
@click="handleTabChange(tab.value)"
|
||||
>
|
||||
{{ tab.label }}({{ tab.count }})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -60,81 +32,107 @@ export default {
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
tabCounts: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
all: 0,
|
||||
'0': 0,
|
||||
'1': 0,
|
||||
'2': 0
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchKeyword: '',
|
||||
selectedStatus: '',
|
||||
statusOptions: [
|
||||
{ label: '进行中', value: '0' },
|
||||
{ label: '已完成', value: '1' },
|
||||
{ label: '已归档', value: '2' }
|
||||
activeTab: 'all',
|
||||
tabs: [
|
||||
{ label: '全部项目', value: 'all', count: 0 },
|
||||
{ label: '进行中', value: '0', count: 0 },
|
||||
{ label: '已完成', value: '1', count: 0 },
|
||||
{ label: '已归档', value: '2', count: 0 }
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tabCounts: {
|
||||
handler(newVal) {
|
||||
this.tabs = this.tabs.map(tab => ({
|
||||
...tab,
|
||||
count: newVal[tab.value] || 0
|
||||
}))
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 搜索 */
|
||||
handleSearch() {
|
||||
this.emitQuery()
|
||||
},
|
||||
/** 状态变化 */
|
||||
handleStatusChange() {
|
||||
/** 标签页切换 */
|
||||
handleTabChange(tabValue) {
|
||||
this.activeTab = tabValue
|
||||
this.emitQuery()
|
||||
},
|
||||
/** 发送查询 */
|
||||
emitQuery() {
|
||||
this.$emit('query', {
|
||||
projectName: this.searchKeyword || null,
|
||||
projectStatus: this.selectedStatus || null
|
||||
status: this.activeTab === 'all' ? null : this.activeTab
|
||||
})
|
||||
},
|
||||
/** 新增 */
|
||||
handleAdd() {
|
||||
this.$emit('add')
|
||||
},
|
||||
/** 导入 */
|
||||
handleImport() {
|
||||
this.$emit('import')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchKeyword(newVal) {
|
||||
if (newVal === '') {
|
||||
this.emitQuery()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-bar-container {
|
||||
margin-bottom: 12px;
|
||||
.search-filter-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
padding: 16px 20px;
|
||||
background: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.search-card {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
.search-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-input-group__append) {
|
||||
background-color: #409EFF;
|
||||
color: white;
|
||||
border-color: #409EFF;
|
||||
.search-input {
|
||||
width: 240px;
|
||||
// Let Element UI's size="small" control the height naturally
|
||||
}
|
||||
|
||||
.tab-filters {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
font-size: 14px;
|
||||
color: #6B7280;
|
||||
cursor: pointer;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background-color: #66b1ff;
|
||||
color: #3B82F6;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #3B82F6;
|
||||
background: #EFF6FF;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-button--medium) {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
<!-- 页面标题 -->
|
||||
<div class="page-header">
|
||||
<h2 class="page-title">初核项目管理</h2>
|
||||
<p class="page-subtitle">管理纪检初核排查项目,跟踪预警信息</p>
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新建项目</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索和操作区 -->
|
||||
<search-bar
|
||||
:show-search="showSearch"
|
||||
:tab-counts="tabCounts"
|
||||
@query="handleQuery"
|
||||
@add="handleAdd"
|
||||
@import="handleImport"
|
||||
/>
|
||||
|
||||
<!-- 项目列表表格 -->
|
||||
@@ -20,8 +19,7 @@
|
||||
:data-list="projectList"
|
||||
:total="total"
|
||||
:page-params="queryParams"
|
||||
@pagination="getList"
|
||||
@detail="handleDetail"
|
||||
@pagination="handlePagination"
|
||||
@enter="handleEnter"
|
||||
@view-result="handleViewResult"
|
||||
@re-analyze="handleReAnalyze"
|
||||
@@ -63,13 +61,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMockProjectList } from "@/api/ccdiProject";
|
||||
import SearchBar from "./components/SearchBar";
|
||||
import ProjectTable from "./components/ProjectTable";
|
||||
import QuickEntry from "./components/QuickEntry";
|
||||
import AddProjectDialog from "./components/AddProjectDialog";
|
||||
import ImportHistoryDialog from "./components/ImportHistoryDialog";
|
||||
import ArchiveConfirmDialog from "./components/ArchiveConfirmDialog";
|
||||
import {listProject, getStatusCounts} from '@/api/ccdiProject'
|
||||
import SearchBar from './components/SearchBar'
|
||||
import ProjectTable from './components/ProjectTable'
|
||||
import QuickEntry from './components/QuickEntry'
|
||||
import AddProjectDialog from './components/AddProjectDialog'
|
||||
import ImportHistoryDialog from './components/ImportHistoryDialog'
|
||||
import ArchiveConfirmDialog from './components/ArchiveConfirmDialog'
|
||||
|
||||
export default {
|
||||
name: "DpcProject",
|
||||
@@ -96,7 +94,14 @@ export default {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
projectName: null,
|
||||
projectStatus: null,
|
||||
status: null
|
||||
},
|
||||
// 标签页数量统计
|
||||
tabCounts: {
|
||||
all: 0,
|
||||
'0': 0,
|
||||
'1': 0,
|
||||
'2': 0
|
||||
},
|
||||
// 新增/编辑弹窗
|
||||
addDialogVisible: false,
|
||||
@@ -115,17 +120,32 @@ export default {
|
||||
methods: {
|
||||
/** 查询项目列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 使用Mock数据
|
||||
getMockProjectList()
|
||||
.then((response) => {
|
||||
this.projectList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.loading = true
|
||||
|
||||
// 并行请求列表数据和状态统计
|
||||
Promise.all([
|
||||
listProject(this.queryParams),
|
||||
getStatusCounts()
|
||||
]).then(([listResponse, countsResponse]) => {
|
||||
// 处理列表数据
|
||||
this.projectList = listResponse.rows
|
||||
this.total = listResponse.total
|
||||
|
||||
// 处理状态统计
|
||||
const counts = countsResponse.data || {}
|
||||
this.tabCounts = {
|
||||
all: counts.all || 0,
|
||||
'0': counts.status0 || 0,
|
||||
'1': counts.status1 || 0,
|
||||
'2': counts.status2 || 0
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
}).catch((error) => {
|
||||
this.loading = false
|
||||
console.error('加载数据失败:', error)
|
||||
this.$modal.msgError('加载数据失败,请稍后重试')
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery(queryParams) {
|
||||
@@ -135,6 +155,14 @@ export default {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 分页事件处理 */
|
||||
handlePagination(pagination) {
|
||||
if (pagination) {
|
||||
this.queryParams.pageNum = pagination.pageNum
|
||||
this.queryParams.pageSize = pagination.pageSize
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.projectForm = this.getEmptyForm();
|
||||
@@ -160,11 +188,9 @@ export default {
|
||||
},
|
||||
/** 提交项目表单 */
|
||||
handleSubmitProject(data) {
|
||||
// 这里应该调用实际的API
|
||||
console.log("提交项目数据:", data);
|
||||
this.$modal.msgSuccess("项目创建成功");
|
||||
this.addDialogVisible = false;
|
||||
this.getList();
|
||||
// 不需要再次调用API,因为AddProjectDialog已经处理了
|
||||
this.addDialogVisible = false
|
||||
this.getList() // 刷新列表
|
||||
},
|
||||
/** 导入历史项目 */
|
||||
handleImport() {
|
||||
@@ -199,11 +225,6 @@ export default {
|
||||
this.addDialogTitle = "创建高风险专项项目";
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
/** 查看详情 */
|
||||
handleDetail(row) {
|
||||
console.log("查看详情:", row);
|
||||
this.$modal.msgInfo("查看项目详情: " + row.projectName);
|
||||
},
|
||||
/** 进入项目 */
|
||||
handleEnter(row) {
|
||||
this.$router.push({
|
||||
@@ -239,30 +260,22 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dpc-project-container {
|
||||
padding: 16px;
|
||||
background: #f0f2f5;
|
||||
padding: 24px;
|
||||
background: #F8F9FA;
|
||||
min-height: calc(100vh - 140px);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 12px;
|
||||
padding: 16px 20px;
|
||||
background: #ffffff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
margin: 4px 0 0 0;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -37,6 +37,7 @@ module.exports = {
|
||||
// detail: https://cli.vuejs.org/config/#devserver-proxy
|
||||
[process.env.VUE_APP_BASE_API]: {
|
||||
target: baseUrl,
|
||||
// target: "http://116.62.17.81:20202",
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||
|
||||
Reference in New Issue
Block a user