修复文件问题 修改bug
This commit is contained in:
BIN
public/excel/dictlist.xlsx
Normal file
BIN
public/excel/dictlist.xlsx
Normal file
Binary file not shown.
30
src/api/basic/basicasynctask.ts
Normal file
30
src/api/basic/basicasynctask.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2025, cyweb All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import request from '/@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取列表
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
export const fetchList = (query?: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/basic/basicAsyncTask/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import request from '/@/utils/request';
|
import request from '/@/utils/request';
|
||||||
|
|
||||||
|
|
||||||
export const exportTeacherInfoBySelf = (data?: any) => {
|
export const makeExportTeacherInfoBySelfTask = (data?: any) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/professional/file/exportTeacherInfoBySelf',
|
url: '/professional/file/makeExportTeacherInfoBySelfTask',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data,
|
data: data,
|
||||||
});
|
});
|
||||||
|
|||||||
106
src/api/purchase/acceptanceItemConfig.ts
Normal file
106
src/api/purchase/acceptanceItemConfig.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from "/@/utils/request"
|
||||||
|
|
||||||
|
// ========== 基础CRUD接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询列表数据
|
||||||
|
* @param query - 查询参数对象
|
||||||
|
* @returns Promise<分页数据>
|
||||||
|
*/
|
||||||
|
export function fetchList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/acceptanceItemConfig/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增数据
|
||||||
|
* @param obj - 要新增的数据对象
|
||||||
|
* @returns Promise<boolean> - 操作结果
|
||||||
|
*/
|
||||||
|
export function addObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/acceptanceItemConfig',
|
||||||
|
method: 'post',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情数据
|
||||||
|
* @param obj - 查询参数对象(包含ID等)
|
||||||
|
* @returns Promise<数据详情>
|
||||||
|
*/
|
||||||
|
export function getObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/acceptanceItemConfig/details',
|
||||||
|
method: 'get',
|
||||||
|
params: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除数据
|
||||||
|
* @param ids - 要删除的ID数组
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function delObjs(ids?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/acceptanceItemConfig',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
* @param obj - 要更新的数据对象
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function putObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/acceptanceItemConfig',
|
||||||
|
method: 'put',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 工具函数 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证字段值唯一性
|
||||||
|
* @param rule - 验证规则对象
|
||||||
|
* @param value - 要验证的值
|
||||||
|
* @param callback - 验证回调函数
|
||||||
|
* @param isEdit - 是否为编辑模式
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // 在表单验证规则中使用
|
||||||
|
* fieldName: [
|
||||||
|
* {
|
||||||
|
* validator: (rule, value, callback) => {
|
||||||
|
* validateExist(rule, value, callback, form.id !== '');
|
||||||
|
* },
|
||||||
|
* trigger: 'blur',
|
||||||
|
* },
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
export function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {
|
||||||
|
// 编辑模式下跳过验证
|
||||||
|
if (isEdit) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否存在相同值
|
||||||
|
getObj({ [rule.field]: value }).then((response) => {
|
||||||
|
const result = response.data;
|
||||||
|
if (result !== null && result.length > 0) {
|
||||||
|
callback(new Error('数据已经存在'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
106
src/api/purchase/puchasingAcceptContent.ts
Normal file
106
src/api/purchase/puchasingAcceptContent.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from "/@/utils/request"
|
||||||
|
|
||||||
|
// ========== 基础CRUD接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询列表数据
|
||||||
|
* @param query - 查询参数对象
|
||||||
|
* @returns Promise<分页数据>
|
||||||
|
*/
|
||||||
|
export function fetchList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptContent/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增数据
|
||||||
|
* @param obj - 要新增的数据对象
|
||||||
|
* @returns Promise<boolean> - 操作结果
|
||||||
|
*/
|
||||||
|
export function addObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptContent',
|
||||||
|
method: 'post',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情数据
|
||||||
|
* @param obj - 查询参数对象(包含ID等)
|
||||||
|
* @returns Promise<数据详情>
|
||||||
|
*/
|
||||||
|
export function getObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptContent/details',
|
||||||
|
method: 'get',
|
||||||
|
params: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除数据
|
||||||
|
* @param ids - 要删除的ID数组
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function delObjs(ids?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptContent',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
* @param obj - 要更新的数据对象
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function putObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptContent',
|
||||||
|
method: 'put',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 工具函数 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证字段值唯一性
|
||||||
|
* @param rule - 验证规则对象
|
||||||
|
* @param value - 要验证的值
|
||||||
|
* @param callback - 验证回调函数
|
||||||
|
* @param isEdit - 是否为编辑模式
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // 在表单验证规则中使用
|
||||||
|
* fieldName: [
|
||||||
|
* {
|
||||||
|
* validator: (rule, value, callback) => {
|
||||||
|
* validateExist(rule, value, callback, form.id !== '');
|
||||||
|
* },
|
||||||
|
* trigger: 'blur',
|
||||||
|
* },
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
export function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {
|
||||||
|
// 编辑模式下跳过验证
|
||||||
|
if (isEdit) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否存在相同值
|
||||||
|
getObj({ [rule.field]: value }).then((response) => {
|
||||||
|
const result = response.data;
|
||||||
|
if (result !== null && result.length > 0) {
|
||||||
|
callback(new Error('数据已经存在'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
106
src/api/purchase/puchasingAcceptTeam.ts
Normal file
106
src/api/purchase/puchasingAcceptTeam.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from "/@/utils/request"
|
||||||
|
|
||||||
|
// ========== 基础CRUD接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询列表数据
|
||||||
|
* @param query - 查询参数对象
|
||||||
|
* @returns Promise<分页数据>
|
||||||
|
*/
|
||||||
|
export function fetchList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptTeam/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增数据
|
||||||
|
* @param obj - 要新增的数据对象
|
||||||
|
* @returns Promise<boolean> - 操作结果
|
||||||
|
*/
|
||||||
|
export function addObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptTeam',
|
||||||
|
method: 'post',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情数据
|
||||||
|
* @param obj - 查询参数对象(包含ID等)
|
||||||
|
* @returns Promise<数据详情>
|
||||||
|
*/
|
||||||
|
export function getObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptTeam/details',
|
||||||
|
method: 'get',
|
||||||
|
params: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除数据
|
||||||
|
* @param ids - 要删除的ID数组
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function delObjs(ids?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptTeam',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
* @param obj - 要更新的数据对象
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function putObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/puchasingAcceptTeam',
|
||||||
|
method: 'put',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 工具函数 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证字段值唯一性
|
||||||
|
* @param rule - 验证规则对象
|
||||||
|
* @param value - 要验证的值
|
||||||
|
* @param callback - 验证回调函数
|
||||||
|
* @param isEdit - 是否为编辑模式
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // 在表单验证规则中使用
|
||||||
|
* fieldName: [
|
||||||
|
* {
|
||||||
|
* validator: (rule, value, callback) => {
|
||||||
|
* validateExist(rule, value, callback, form.id !== '');
|
||||||
|
* },
|
||||||
|
* trigger: 'blur',
|
||||||
|
* },
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
export function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {
|
||||||
|
// 编辑模式下跳过验证
|
||||||
|
if (isEdit) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否存在相同值
|
||||||
|
getObj({ [rule.field]: value }).then((response) => {
|
||||||
|
const result = response.data;
|
||||||
|
if (result !== null && result.length > 0) {
|
||||||
|
callback(new Error('数据已经存在'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
173
src/api/purchase/purchasingAccept.ts
Normal file
173
src/api/purchase/purchasingAccept.ts
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
import request from "/@/utils/request"
|
||||||
|
|
||||||
|
// ========== 基础CRUD接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询列表数据
|
||||||
|
* @param query - 查询参数对象
|
||||||
|
* @returns Promise<分页数据>
|
||||||
|
*/
|
||||||
|
export function fetchList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增数据
|
||||||
|
* @param obj - 要新增的数据对象
|
||||||
|
* @returns Promise<boolean> - 操作结果
|
||||||
|
*/
|
||||||
|
export function addObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept',
|
||||||
|
method: 'post',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情数据
|
||||||
|
* @param obj - 查询参数对象(包含ID等)
|
||||||
|
* @returns Promise<数据详情>
|
||||||
|
*/
|
||||||
|
export function getObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/details',
|
||||||
|
method: 'get',
|
||||||
|
params: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除数据
|
||||||
|
* @param ids - 要删除的ID数组
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function delObjs(ids?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新数据
|
||||||
|
* @param obj - 要更新的数据对象
|
||||||
|
* @returns Promise<操作结果>
|
||||||
|
*/
|
||||||
|
export function putObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept',
|
||||||
|
method: 'put',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 履约验收流程接口 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第一步:保存履约验收公共配置,按分期次数自动生成批次
|
||||||
|
*/
|
||||||
|
export function saveCommonConfig(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/saveCommonConfig',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取履约验收公共配置及批次列表
|
||||||
|
*/
|
||||||
|
export function getCommonConfigWithBatches(purchaseId: string) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/commonConfigWithBatches',
|
||||||
|
method: 'get',
|
||||||
|
params: { purchaseId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第二步:更新单个批次
|
||||||
|
*/
|
||||||
|
export function updateBatch(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/updateBatch',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验收详情(含验收内容、验收小组)
|
||||||
|
*/
|
||||||
|
export function getDetail(purchaseId: string, batch?: number) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/detail',
|
||||||
|
method: 'get',
|
||||||
|
params: { purchaseId, batch }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许填报方式(金额<30万)
|
||||||
|
*/
|
||||||
|
export function canFillForm(purchaseId: string) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingAccept/canFillForm',
|
||||||
|
method: 'get',
|
||||||
|
params: { purchaseId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据品目类型获取验收项配置
|
||||||
|
*/
|
||||||
|
export function getAcceptanceItems(acceptanceType: string) {
|
||||||
|
return request({
|
||||||
|
url: `/purchase/acceptanceItemConfig/listByType/${acceptanceType}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 工具函数 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证字段值唯一性
|
||||||
|
* @param rule - 验证规则对象
|
||||||
|
* @param value - 要验证的值
|
||||||
|
* @param callback - 验证回调函数
|
||||||
|
* @param isEdit - 是否为编辑模式
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // 在表单验证规则中使用
|
||||||
|
* fieldName: [
|
||||||
|
* {
|
||||||
|
* validator: (rule, value, callback) => {
|
||||||
|
* validateExist(rule, value, callback, form.id !== '');
|
||||||
|
* },
|
||||||
|
* trigger: 'blur',
|
||||||
|
* },
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
export function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {
|
||||||
|
// 编辑模式下跳过验证
|
||||||
|
if (isEdit) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询是否存在相同值
|
||||||
|
getObj({ [rule.field]: value }).then((response) => {
|
||||||
|
const result = response.data;
|
||||||
|
if (result !== null && result.length > 0) {
|
||||||
|
callback(new Error('数据已经存在'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
188
src/assets/styles/page-cards.scss
Normal file
188
src/assets/styles/page-cards.scss
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* 列表页卡片布局公共样式(筛选卡片 + 内容卡片 + 表头)
|
||||||
|
* 各业务模块通用,不限于专业模块
|
||||||
|
*
|
||||||
|
* 使用:@import '/@/assets/styles/page-cards.scss';
|
||||||
|
* 模板类名:.page-cards > .page-wrapper > .search-card / .content-card
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 页面整体
|
||||||
|
.page-cards {
|
||||||
|
padding: 12px;
|
||||||
|
min-height: 100%;
|
||||||
|
background: var(--el-bg-color-page, #f5f6f8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面包装器
|
||||||
|
.page-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选卡片
|
||||||
|
.search-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
background: var(--el-bg-color);
|
||||||
|
|
||||||
|
:deep(.el-card__body) {
|
||||||
|
padding: 18px 20px 5px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列表内容卡片
|
||||||
|
.content-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||||
|
background: var(--el-bg-color);
|
||||||
|
|
||||||
|
:deep(.el-card__header) {
|
||||||
|
padding: 20px 20px 15px;
|
||||||
|
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-card__body) {
|
||||||
|
padding: 15px 20px 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
|
||||||
|
.title-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小屏幕适配(≤768px)
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.page-cards {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-wrapper {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-card :deep(.el-card__body) {
|
||||||
|
padding: 12px 14px 4px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card :deep(.el-card__header) {
|
||||||
|
padding: 14px 14px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card :deep(.el-card__body) {
|
||||||
|
padding: 12px 14px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 14px;
|
||||||
|
.title-icon {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-group {
|
||||||
|
gap: 8px;
|
||||||
|
// 按钮间距
|
||||||
|
.el-button {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 超小屏幕适配(≤576px)
|
||||||
|
@media screen and (max-width: 576px) {
|
||||||
|
.page-cards {
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-wrapper {
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-card :deep(.el-card__body) {
|
||||||
|
padding: 10px 12px 14px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card :deep(.el-card__header) {
|
||||||
|
padding: 12px 12px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-card :deep(.el-card__body) {
|
||||||
|
padding: 10px 12px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.action-group {
|
||||||
|
gap: 6px;
|
||||||
|
// 按钮间距
|
||||||
|
.el-button {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-left: none;
|
||||||
|
border-top: 1px solid var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,25 +2,21 @@
|
|||||||
<el-tag
|
<el-tag
|
||||||
:type="type"
|
:type="type"
|
||||||
:size="size"
|
:size="size"
|
||||||
|
:effect="effect"
|
||||||
:class="['clickable-tag', { 'has-action': actualRightIcon !== null}]"
|
:class="['clickable-tag', { 'has-action': actualRightIcon !== null}]"
|
||||||
:style="{ width: width ? `${width}px` : 'auto' }"
|
:style="{ width: width ? `${width}px` : 'auto' }"
|
||||||
@click="handleClick">
|
@click="handleClick">
|
||||||
<!-- 左侧图标 -->
|
<!-- 左侧图标:支持 Vue 组件(Element 图标,线条)或字符串(如 FontAwesome class,可实心) -->
|
||||||
<el-icon
|
<i v-if="leftIcon && isLeftIconString" :class="leftIcon" class="left-icon left-icon--fa"></i>
|
||||||
v-if="leftIcon"
|
<el-icon v-else-if="leftIcon" :size="size" class="left-icon">
|
||||||
:size="size"
|
|
||||||
class="left-icon">
|
|
||||||
<component :is="leftIcon" />
|
<component :is="leftIcon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|
||||||
<!-- 主要内容 -->
|
<!-- 主要内容 -->
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<!-- 中间图标(如警告图标) -->
|
<!-- 中间图标:支持 Vue 组件或字符串(如 FontAwesome class) -->
|
||||||
<el-icon
|
<i v-if="middleIcon && isMiddleIconString" :class="middleIcon" class="middle-icon middle-icon--fa"></i>
|
||||||
v-if="middleIcon"
|
<el-icon v-else-if="middleIcon" :size="size" class="middle-icon">
|
||||||
:size="size"
|
|
||||||
class="middle-icon">
|
|
||||||
<component :is="middleIcon" />
|
<component :is="middleIcon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|
||||||
@@ -36,26 +32,32 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { Right } from '@element-plus/icons-vue'
|
import { InfoFilled, Right } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type?: 'success' | 'info' | 'warning' | 'danger' | 'primary'
|
type?: 'success' | 'info' | 'warning' | 'danger' | 'primary'
|
||||||
size?: 'large' | 'default' | 'small'
|
size?: 'large' | 'default' | 'small'
|
||||||
leftIcon?: any // 左侧图标组件
|
effect?: 'dark' | 'light' | 'plain' // 主题,与 el-tag 一致
|
||||||
middleIcon?: any // 中间图标组件(如警告图标)
|
leftIcon?: any // 左侧图标:Vue 组件(Element 图标)或字符串(如 FontAwesome class 'fa-solid fa-circle-xmark')
|
||||||
rightIcon?: any // 右侧图标组件(默认为 Right null 则不显示)
|
middleIcon?: any // 中间图标:Vue 组件或字符串(如 FontAwesome class)
|
||||||
|
rightIcon?: any // 右侧图标:默认 InfoFilled(表示「可查看详情」);传 null 不显示;也可用 Right(跳转)、View(查看)等
|
||||||
width?: string | number // 自定义宽度
|
width?: string | number // 自定义宽度
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
size: 'default',
|
size: 'default',
|
||||||
|
effect: 'light',
|
||||||
leftIcon: undefined,
|
leftIcon: undefined,
|
||||||
middleIcon: undefined,
|
middleIcon: undefined,
|
||||||
rightIcon: undefined,
|
rightIcon: undefined,
|
||||||
width: undefined
|
width: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 左侧/中间图标为字符串时(如 FontAwesome class)用 <i> 渲染,与 AuditState 实心一致
|
||||||
|
const isLeftIconString = computed(() => typeof props.leftIcon === 'string')
|
||||||
|
const isMiddleIconString = computed(() => typeof props.middleIcon === 'string')
|
||||||
|
|
||||||
// 获取实际的右侧图标:未传值时使用默认图标,传 null 则不显示
|
// 获取实际的右侧图标:未传值时使用默认图标,传 null 则不显示
|
||||||
const actualRightIcon = computed(() => {
|
const actualRightIcon = computed(() => {
|
||||||
if (props.rightIcon === null) return null
|
if (props.rightIcon === null) return null
|
||||||
@@ -80,6 +82,11 @@ export default {
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.clickable-tag {
|
.clickable-tag {
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
.left-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
// 覆盖 el-tag 的内部结构
|
// 覆盖 el-tag 的内部结构
|
||||||
:deep(.el-tag__content) {
|
:deep(.el-tag__content) {
|
||||||
@@ -91,10 +98,8 @@ export default {
|
|||||||
// 有交互功能时才显示手型光标和悬停效果
|
// 有交互功能时才显示手型光标和悬停效果
|
||||||
&.has-action {
|
&.has-action {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
.right-icon {
|
.right-icon {
|
||||||
transform: translateX(2px);
|
transform: translateX(2px);
|
||||||
}
|
}
|
||||||
@@ -103,7 +108,6 @@ export default {
|
|||||||
.middle-icon {
|
.middle-icon {
|
||||||
animation: pulse 1.5s ease-in-out infinite;
|
animation: pulse 1.5s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-icon {
|
.right-icon {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
|||||||
@@ -1,27 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="search-form__wrap" :class="{ 'search-form__wrap--with-title': filterTitle }">
|
<div class="search-form__wrap" :class="{ 'search-form__wrap--with-title': filterTitle && props.showFilterTitle }">
|
||||||
<div class="search-form__bar">
|
<div class="search-form__bar">
|
||||||
<div class="search-form-container">
|
<div class="search-form-container">
|
||||||
<el-form :model="formModel" ref="formRef" :inline="true" @keyup.enter="handleKeyupEnter" :label-width="labelWidth">
|
<el-form :model="formModel" ref="formRef" :inline="true" @keyup.enter="handleKeyupEnter" :label-width="labelWidth">
|
||||||
<!-- 筛选 + 展开更多 放在同一表单项内,保证垂直对齐 -->
|
<!-- 筛选 + 展开更多 放在同一表单项内,保证垂直对齐 -->
|
||||||
<el-form-item v-if="filterTitle || hasCollapsibleItems" class="search-form__left-group">
|
<el-form-item v-if="(filterTitle && props.showFilterTitle) || hasCollapsibleItems" class="search-form__left-group">
|
||||||
<div class="search-form__left-inner">
|
<div class="search-form__left-inner">
|
||||||
<span v-if="filterTitle" class="search-form__title">
|
<span v-if="filterTitle && props.showFilterTitle" class="search-form__title" :style="{ marginRight: hasCollapsibleItems ? '12px' : '0' }">
|
||||||
<el-icon class="search-form__title-icon"><Search /></el-icon>
|
<el-icon class="search-form__title-icon"><Search /></el-icon>
|
||||||
{{ filterTitle }}
|
{{ filterTitle }}
|
||||||
</span>
|
</span>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="hasCollapsibleItems"
|
v-if="hasCollapsibleItems"
|
||||||
link
|
|
||||||
type="primary"
|
type="primary"
|
||||||
class="toggle-btn"
|
class="toggle-btn"
|
||||||
@click="toggleExpand"
|
@click="toggleExpand"
|
||||||
|
round
|
||||||
>
|
>
|
||||||
<el-icon style="margin-right: 4px">
|
<el-icon
|
||||||
<ArrowUp v-if="isExpanded" />
|
class="toggle-btn__icon"
|
||||||
<ArrowDown v-else />
|
:class="{ 'toggle-btn__icon--expanded': isExpanded }"
|
||||||
|
>
|
||||||
|
<CaretBottom />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
{{ isExpanded ? '收起' : '展开更多' }}
|
<span class="toggle-btn__text">
|
||||||
|
{{ isExpanded ? '收起筛选' : '更多筛选' }}
|
||||||
|
</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -44,7 +48,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts" name="search-form">
|
<script setup lang="ts" name="search-form">
|
||||||
import { ref, watch, computed, onMounted, nextTick } from 'vue';
|
import { ref, watch, computed, onMounted, nextTick } from 'vue';
|
||||||
import { ArrowUp, ArrowDown, Search } from '@element-plus/icons-vue';
|
import { CaretBottom, Search } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +56,14 @@ const props = defineProps({
|
|||||||
*/
|
*/
|
||||||
filterTitle: {
|
filterTitle: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '筛选',
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 是否显示筛选标题文案(仅控制左侧「筛选」文字和图标)
|
||||||
|
*/
|
||||||
|
showFilterTitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 表单数据模型
|
* 表单数据模型
|
||||||
@@ -227,7 +238,6 @@ defineExpose({
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
margin-right: 12px;
|
|
||||||
height: 32px;
|
height: 32px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -261,13 +271,29 @@ defineExpose({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-form__left-inner :deep(.toggle-btn__icon) {
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
}
|
||||||
|
.search-form__left-inner :deep(.toggle-btn__icon--expanded) {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
.search-form__left-inner :deep(.toggle-btn) {
|
.search-form__left-inner :deep(.toggle-btn) {
|
||||||
font-size: 14px;
|
padding: 0 12px;
|
||||||
font-weight: 500;
|
|
||||||
height: 32px;
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 6px;
|
font-weight: 500;
|
||||||
|
// 默认态直接使用 hover 的视觉样式
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
background-color: var(--el-fill-color-lighter);
|
||||||
|
border: 1px solid var(--el-color-primary-light-7);
|
||||||
|
transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-form-item:not(:has(.el-button))) {
|
:deep(.el-form-item:not(:has(.el-button))) {
|
||||||
|
|||||||
150
src/layout/navBars/breadcrumb/asyncTaskDrawer.vue
Normal file
150
src/layout/navBars/breadcrumb/asyncTaskDrawer.vue
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
v-model="visible"
|
||||||
|
title="上传和下载任务"
|
||||||
|
direction="rtl"
|
||||||
|
size="50%"
|
||||||
|
destroy-on-close
|
||||||
|
@open="onOpen"
|
||||||
|
>
|
||||||
|
<el-tabs v-model="activeTab">
|
||||||
|
<el-tab-pane label="上传" name="upload" />
|
||||||
|
<el-tab-pane label="下载" name="download" />
|
||||||
|
<el-tab-pane label="其他" name="other" />
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<div class="task-table-wrap">
|
||||||
|
<el-table
|
||||||
|
v-loading="loading[activeTab]"
|
||||||
|
:data="list[activeTab]"
|
||||||
|
height="calc(100vh - 240px)"
|
||||||
|
row-key="id"
|
||||||
|
:empty-text="emptyText"
|
||||||
|
size="small"
|
||||||
|
stripe
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
|
>
|
||||||
|
<el-table-column label="所属模块" prop="moduleName" width="120" show-overflow-tooltip />
|
||||||
|
<el-table-column label="任务类型" prop="typeLabel" width="100" show-overflow-tooltip />
|
||||||
|
<el-table-column label="任务名称" prop="detailType" min-width="150" show-overflow-tooltip />
|
||||||
|
<el-table-column label="任务状态" align="center" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag>{{ row.status }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="时间" width="150" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatTime(row) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="task-pagination">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination[activeTab].current"
|
||||||
|
v-model:page-size="pagination[activeTab].size"
|
||||||
|
:page-sizes="[10, 20, 50]"
|
||||||
|
:total="pagination[activeTab].total"
|
||||||
|
layout="prev, pager, next, sizes"
|
||||||
|
small
|
||||||
|
@current-change="onPageChange"
|
||||||
|
@size-change="onSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, watch, computed } from 'vue'
|
||||||
|
import { fetchList } from '/@/api/basic/basicasynctask'
|
||||||
|
|
||||||
|
type TaskTab = 'upload' | 'download' | 'other'
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const activeTab = ref<TaskTab>('upload')
|
||||||
|
const loading = reactive<Record<TaskTab, boolean>>({ upload: false, download: false, other: false })
|
||||||
|
const list = reactive<Record<TaskTab, any[]>>({ upload: [], download: [], other: [] })
|
||||||
|
const pagination = reactive<Record<TaskTab, { current: number; size: number; total: number }>>({
|
||||||
|
upload: { current: 1, size: 10, total: 0 },
|
||||||
|
download: { current: 1, size: 10, total: 0 },
|
||||||
|
other: { current: 1, size: 10, total: 0 },
|
||||||
|
})
|
||||||
|
|
||||||
|
/** Tab 对应接口 type:1 上传 2 下载 3 其他 */
|
||||||
|
const TAB_TYPE_MAP: Record<TaskTab, number> = { upload: 1, download: 2, other: 3 }
|
||||||
|
const EMPTY_TEXT_MAP: Record<TaskTab, string> = { upload: '暂无上传任务', download: '暂无下载任务', other: '暂无其他任务' }
|
||||||
|
|
||||||
|
// 表格样式,参考主列表页通用样式
|
||||||
|
const tableStyle = {
|
||||||
|
cellStyle: { textAlign: 'center' },
|
||||||
|
headerCellStyle: {
|
||||||
|
textAlign: 'center',
|
||||||
|
background: 'var(--el-table-row-hover-bg-color)',
|
||||||
|
color: 'var(--el-text-color-primary)',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyText = computed(() => EMPTY_TEXT_MAP[activeTab.value])
|
||||||
|
|
||||||
|
const loadList = async () => {
|
||||||
|
const type = activeTab.value
|
||||||
|
const p = pagination[type]
|
||||||
|
loading[type] = true
|
||||||
|
try {
|
||||||
|
const res = await fetchList({ type: TAB_TYPE_MAP[type], current: p.current, size: p.size })
|
||||||
|
const data = res?.data ?? res
|
||||||
|
const records = data?.records ?? []
|
||||||
|
const total = data?.total ?? 0
|
||||||
|
list[type] = Array.isArray(records) ? records : []
|
||||||
|
p.total = Number(total) || 0
|
||||||
|
} catch {
|
||||||
|
list[type] = []
|
||||||
|
} finally {
|
||||||
|
loading[type] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPageChange = (page: number) => {
|
||||||
|
pagination[activeTab.value].current = page
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSizeChange = (size: number) => {
|
||||||
|
pagination[activeTab.value].size = size
|
||||||
|
pagination[activeTab.value].current = 1
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onOpen = () => {
|
||||||
|
loadList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换 Tab 时加载对应列表
|
||||||
|
watch(activeTab, () => {
|
||||||
|
if (visible.value) loadList()
|
||||||
|
})
|
||||||
|
|
||||||
|
const formatTime = (item: any) => {
|
||||||
|
const t = item?.createTime ?? item?.create_time ?? item?.updateTime ?? item?.update_time ?? ''
|
||||||
|
return t ? (t.slice(0, 16).replace('T', ' ')) : '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = () => {
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.task-table-wrap {
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.task-pagination {
|
||||||
|
padding: 12px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }">
|
<div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }">
|
||||||
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
|
<!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
|
||||||
<div class="layout-navbars-breadcrumb-user-icon">
|
<div class="layout-navbars-breadcrumb-user-icon">
|
||||||
<i class="iconfont" :class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('user.title1')"></i>
|
<i class="iconfont" :class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('user.title1')"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -10,7 +10,12 @@
|
|||||||
<el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
|
<el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown> -->
|
||||||
|
<div class="layout-navbars-breadcrumb-user-icon" @click="onAsyncTaskClick">
|
||||||
|
<el-icon title="上传和下载任务">
|
||||||
|
<ele-FolderOpened />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
<div class="layout-navbars-breadcrumb-user-icon" @click="onLockClick">
|
<div class="layout-navbars-breadcrumb-user-icon" @click="onLockClick">
|
||||||
<el-icon :title="$t('layout.threeLockScreenTime')">
|
<el-icon :title="$t('layout.threeLockScreenTime')">
|
||||||
<ele-Lock />
|
<ele-Lock />
|
||||||
@@ -76,6 +81,7 @@
|
|||||||
<personal-drawer ref="personalDrawerRef"></personal-drawer>
|
<personal-drawer ref="personalDrawerRef"></personal-drawer>
|
||||||
|
|
||||||
<change-role ref="ChangeRoleRef" />
|
<change-role ref="ChangeRoleRef" />
|
||||||
|
<AsyncTaskDrawer ref="asyncTaskDrawerRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -97,6 +103,8 @@ import {useFlowJob} from "/@/flow/stores/flowJob";
|
|||||||
|
|
||||||
const ChangeRoleRef = ref()
|
const ChangeRoleRef = ref()
|
||||||
const ChangeRole = defineAsyncComponent(() => import('/@/views/admin/system/role/change-role.vue'))
|
const ChangeRole = defineAsyncComponent(() => import('/@/views/admin/system/role/change-role.vue'))
|
||||||
|
const asyncTaskDrawerRef = ref()
|
||||||
|
const AsyncTaskDrawer = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/asyncTaskDrawer.vue'))
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const GlobalWebsocket = defineAsyncComponent(() => import('/@/components/Websocket/index.vue'));
|
const GlobalWebsocket = defineAsyncComponent(() => import('/@/components/Websocket/index.vue'));
|
||||||
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
|
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
|
||||||
@@ -207,6 +215,10 @@ const onHandleCommandClick = (path: string) => {
|
|||||||
const onSearchClick = () => {
|
const onSearchClick = () => {
|
||||||
searchRef.value.openSearch();
|
searchRef.value.openSearch();
|
||||||
};
|
};
|
||||||
|
// 上传/下载任务点击
|
||||||
|
const onAsyncTaskClick = () => {
|
||||||
|
asyncTaskDrawerRef.value?.open();
|
||||||
|
};
|
||||||
// 语言切换
|
// 语言切换
|
||||||
const onLanguageChange = (lang: string) => {
|
const onLanguageChange = (lang: string) => {
|
||||||
Local.remove('themeConfig');
|
Local.remove('themeConfig');
|
||||||
@@ -241,6 +253,16 @@ const getIsDot = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 登录后若存储中无角色信息则弹出角色切换框
|
||||||
|
const openChangeRoleIfMissing = () => {
|
||||||
|
const hasRole = Local.get('roleCode') && Local.get('roleName') && Local.get('roleId')
|
||||||
|
if (!hasRole) {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => ChangeRoleRef.value?.open(), 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (Local.get('themeConfig')) {
|
if (Local.get('themeConfig')) {
|
||||||
@@ -248,8 +270,8 @@ onMounted(() => {
|
|||||||
initI18nOrSize('globalI18n', 'disabledI18n');
|
initI18nOrSize('globalI18n', 'disabledI18n');
|
||||||
}
|
}
|
||||||
useFlowJob().topJobList()
|
useFlowJob().topJobList()
|
||||||
|
getIsDot()
|
||||||
getIsDot();
|
openChangeRoleIfMissing()
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ body,
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.layout-pd {
|
.layout-pd {
|
||||||
padding: 10px !important;
|
padding: 12px !important;
|
||||||
background: linear-gradient(135deg,#f5f7fa,#e9ecef);
|
background: linear-gradient(135deg,#f5f7fa,#e9ecef);
|
||||||
}
|
}
|
||||||
.layout-flex {
|
.layout-flex {
|
||||||
|
|||||||
@@ -439,6 +439,12 @@
|
|||||||
background-color: #f5f7ff;
|
background-color: #f5f7ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 表格单元格内边距(全局)- 左右用默认,上下 9px */
|
||||||
|
.el-table .el-table__body td,
|
||||||
|
.el-table .el-table__header th {
|
||||||
|
padding: 9px 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* scrollbar
|
/* scrollbar
|
||||||
------------------------------- */
|
------------------------------- */
|
||||||
.el-scrollbar__bar {
|
.el-scrollbar__bar {
|
||||||
|
|||||||
@@ -1,60 +1,86 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="visible" title="角色切换" width="50%">
|
<el-dialog
|
||||||
|
v-model="visible"
|
||||||
|
title="角色切换"
|
||||||
|
width="50%"
|
||||||
|
:show-close="false"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
:before-close="handleBeforeClose"
|
||||||
|
>
|
||||||
<el-form>
|
<el-form>
|
||||||
<!-- <el-form-item label="学校">-->
|
<!-- <el-form-item label="学校">-->
|
||||||
<!-- <el-tag>{{schoolName}}</el-tag>-->
|
<!-- <el-tag>{{schoolName}}</el-tag>-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<el-form-item label="角色">
|
<el-form-item label="角色" class="role-form-item">
|
||||||
<el-radio-group v-model="radio">
|
<el-radio-group v-model="radio" class="role-radio-group" @change="handleChangeRole">
|
||||||
<el-radio-button v-for="(item,index) in allRole" :key="index" :label="item.roleCode" @click.native="handleChangeRole(item.roleCode)">{{item.roleName}}</el-radio-button>
|
<el-radio-button
|
||||||
|
v-for="item in allRole"
|
||||||
|
:key="item.roleCode"
|
||||||
|
:label="item.roleCode"
|
||||||
|
>
|
||||||
|
{{ item.roleName }}
|
||||||
|
</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<!-- <el-button type="primary" @click="handleChangeRole">切换</el-button>-->
|
<!-- <el-button type="primary" @click="handleChangeRole">切换</el-button>-->
|
||||||
<el-button @click="visible=false">关 闭</el-button>
|
<el-button @click="handleFooterClose">关 闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { listAllRole } from '/@/api/admin/role'
|
import { listAllRole } from '/@/api/admin/role'
|
||||||
import {Local, Session} from '/@/utils/storage';
|
import { Local } from '/@/utils/storage'
|
||||||
import {useMessage} from "/@/hooks/message";
|
import { useMessage } from '/@/hooks/message'
|
||||||
// import {querySchoolName} from "/@/api/admin/tenant"
|
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const radio = ref('')
|
const radio = ref('')
|
||||||
const allRole=reactive([])
|
const allRole = reactive<any[]>([])
|
||||||
// const schoolName=ref('')
|
|
||||||
|
|
||||||
const open = () => {
|
const open = () => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
// handleQuerySchoolName()
|
listAllRole().then((res) => {
|
||||||
listAllRole().then(res=>{
|
|
||||||
Object.assign(allRole, res.data)
|
Object.assign(allRole, res.data)
|
||||||
radio.value=Local.get("roleCode")
|
radio.value = Local.get('roleCode')
|
||||||
visible.value = true
|
visible.value = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handleChangeRole=(label:any)=>{
|
|
||||||
let obj:any=allRole.find((v:any) => v.roleCode == label)
|
const canClose = () => {
|
||||||
Local.set("roleCode",obj.roleCode)
|
if (!radio.value) {
|
||||||
Local.set("roleName",obj.roleName)
|
useMessage().warning('请选择一个角色')
|
||||||
Local.set("roleId",obj.roleId)
|
return false
|
||||||
useMessage().success("操作成功")
|
}
|
||||||
setTimeout(()=>{
|
return true
|
||||||
window.location.reload()
|
|
||||||
},500)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleQuerySchoolName=()=>{
|
const handleBeforeClose = (done: () => void) => {
|
||||||
// querySchoolName({id:Session.get("tenantId")}).then((res:any)=>{
|
if (!canClose()) return
|
||||||
// schoolName.value=res.data
|
done()
|
||||||
// })
|
}
|
||||||
|
|
||||||
|
const handleFooterClose = () => {
|
||||||
|
if (!canClose()) return
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChangeRole = (label: string) => {
|
||||||
|
const obj = allRole.find((v: any) => v.roleCode === label)
|
||||||
|
if (!obj) return
|
||||||
|
Local.set('roleCode', obj.roleCode)
|
||||||
|
Local.set('roleName', obj.roleName)
|
||||||
|
Local.set('roleId', obj.roleId)
|
||||||
|
useMessage().success('操作成功')
|
||||||
|
setTimeout(() => {
|
||||||
|
// 切换角色后统一回到首页,避免停留在诸如 jsonflow/run-job/do-job 等内部路由
|
||||||
|
window.location.hash = '#/'
|
||||||
|
window.location.reload()
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@@ -62,6 +88,28 @@ defineExpose({
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
|
.role-form-item {
|
||||||
|
:deep(.el-form-item__content) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.role-radio-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
/* 每个按钮独立边框,换行后左侧也有边线 */
|
||||||
|
:deep(.el-radio-button) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
:deep(.el-radio-button__inner) {
|
||||||
|
border-radius: 6px !important;
|
||||||
|
border: 1px solid var(--el-border-color) !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
:deep(.el-radio-button.is-active .el-radio-button__inner) {
|
||||||
|
border-color: var(--el-color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="160px" class="accept-batch-form">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="验收方式" prop="acceptType">
|
||||||
|
<el-radio-group v-model="form.acceptType" :disabled="readonly">
|
||||||
|
<el-radio label="1">填写履约验收评价表</el-radio>
|
||||||
|
<el-radio label="2" :disabled="!canFill">上传履约验收评价表</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
<div v-if="!canFill" class="el-form-item__tip">金额≥30万,仅支持上传模版</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="验收日期" prop="acceptDate">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="form.acceptDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="请选择"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 填报方式:验收内容表格 -->
|
||||||
|
<template v-if="form.acceptType === '1' && canFill">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="验收内容" prop="acceptContents">
|
||||||
|
<el-table :data="form.acceptContents" border size="small" max-height="260" class="accept-content-table">
|
||||||
|
<el-table-column prop="itemName" label="验收项" >
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{row.itemName}}
|
||||||
|
<el-input
|
||||||
|
v-if="row.type === 'input'"
|
||||||
|
v-model="row.remark"
|
||||||
|
placeholder="请输入"
|
||||||
|
size="small"
|
||||||
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="isQualified" label="合格/不合格" width="140" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-radio-group v-model="row.isQualified" size="small" :disabled="readonly">
|
||||||
|
<el-radio label="1">合格</el-radio>
|
||||||
|
<el-radio label="0">不合格</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
</el-table>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 上传方式 -->
|
||||||
|
<template v-if="form.acceptType === '2'">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="履约验收模版" prop="templateFileIds">
|
||||||
|
<UploadFile
|
||||||
|
v-model="templateFileIdsStr"
|
||||||
|
:limit="1"
|
||||||
|
:data="{ purchaseId: purchaseId || '', fileType: '110' }"
|
||||||
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 验收小组 -->
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="验收小组" prop="acceptTeam">
|
||||||
|
<div class="team-list">
|
||||||
|
<div v-for="(m, idx) in form.acceptTeam" :key="idx" class="team-row">
|
||||||
|
<el-input v-model="m.name" placeholder="姓名" size="small" style="width:120px" :disabled="readonly" />
|
||||||
|
<el-input v-model="m.deptName" placeholder="部门" size="small" style="width:160px" :disabled="readonly" />
|
||||||
|
<el-button v-if="!readonly && form.acceptTeam.length > 3" type="danger" link size="small" @click="removeTeam(idx)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button v-if="!readonly" type="primary" link size="small" @click="addTeam">+ 增加成员</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="el-form-item__tip">至少3人,且为单数</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入" :disabled="readonly" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, watch } from 'vue'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
modelValue: Record<string, any>
|
||||||
|
canFill: boolean
|
||||||
|
readonly?: boolean
|
||||||
|
purchaseId?: string
|
||||||
|
acceptanceItems?: any[]
|
||||||
|
}>(),
|
||||||
|
{ readonly: false, canFill: true, purchaseId: '' }
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const templateFileIdsStr = ref('')
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
acceptType: '1',
|
||||||
|
acceptDate: '',
|
||||||
|
acceptContents: [] as any[],
|
||||||
|
acceptTeam: [
|
||||||
|
{ name: '', deptCode: '', deptName: '' },
|
||||||
|
{ name: '', deptCode: '', deptName: '' },
|
||||||
|
{ name: '', deptCode: '', deptName: '' },
|
||||||
|
] as any[],
|
||||||
|
templateFileIds: [] as string[],
|
||||||
|
remark: '',
|
||||||
|
...props.modelValue,
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.modelValue, (val) => Object.assign(form, val || {}), { deep: true })
|
||||||
|
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
||||||
|
|
||||||
|
watch(() => props.acceptanceItems, (items) => {
|
||||||
|
if (items?.length && form.acceptContents.length === 0) {
|
||||||
|
form.acceptContents = items.map((it: any) => ({
|
||||||
|
configId: it.id,
|
||||||
|
itemName: it.itemName,
|
||||||
|
type: it.type,
|
||||||
|
isQualified: '1',
|
||||||
|
remark: '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
watch(templateFileIdsStr, (s) => {
|
||||||
|
const arr = s ? s.split(',').map((x: string) => x.trim()).filter(Boolean) : []
|
||||||
|
if (JSON.stringify(form.templateFileIds) !== JSON.stringify(arr)) {
|
||||||
|
form.templateFileIds = arr
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => form.templateFileIds, (arr) => {
|
||||||
|
if (Array.isArray(arr) && arr.length) templateFileIdsStr.value = arr.join(',')
|
||||||
|
}, { immediate: true, deep: true })
|
||||||
|
|
||||||
|
const addTeam = () => {
|
||||||
|
form.acceptTeam.push({ name: '', deptCode: '', deptName: '' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeTeam = (idx: number) => {
|
||||||
|
form.acceptTeam.splice(idx, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules: FormRules = {
|
||||||
|
acceptType: [{ required: true, message: '请选择验收方式', trigger: 'change' }],
|
||||||
|
acceptDate: [{ required: true, message: '请选择验收日期', trigger: 'change' }],
|
||||||
|
}
|
||||||
|
|
||||||
|
const validate = () => formRef.value?.validate()
|
||||||
|
|
||||||
|
defineExpose({ validate, form })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.accept-batch-form :deep(.el-form-item) {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.accept-content-table :deep(.el-table__body td) {
|
||||||
|
padding: 10px 0;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
.team-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.team-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.el-form-item__tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px" class="accept-common-form compact-form">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="项目名称">
|
||||||
|
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="需求部门">
|
||||||
|
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="是否签订合同" prop="hasContract">
|
||||||
|
<el-radio-group v-model="form.hasContract">
|
||||||
|
<el-radio label="0">否</el-radio>
|
||||||
|
<el-radio label="1">是</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="form.hasContract === '1'">
|
||||||
|
<el-form-item label="合同" prop="contractId">
|
||||||
|
<el-input v-model="form.contractId" placeholder="请选择合同(待对接合同接口)" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="是否分期验收" prop="isInstallment">
|
||||||
|
<el-radio-group v-model="form.isInstallment">
|
||||||
|
<el-radio label="0">否</el-radio>
|
||||||
|
<el-radio label="1">是</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="form.isInstallment === '1'">
|
||||||
|
<el-form-item label="分期次数" prop="totalPhases">
|
||||||
|
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="供应商名称" prop="supplierName">
|
||||||
|
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="供应商联系人及电话" prop="supplierContact">
|
||||||
|
<el-input v-model="form.supplierContact" placeholder="请输入" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="采购人员" prop="purchaserId">
|
||||||
|
<org-selector v-model:orgList="purchaserList" type="user" :multiple="false" @update:orgList="onPurchaserChange" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="资产管理员" prop="assetAdminId">
|
||||||
|
<org-selector v-model:orgList="assetAdminList" type="user" :multiple="false" @update:orgList="onAssetAdminChange" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, watch } from 'vue'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: Record<string, any>
|
||||||
|
projectName?: string
|
||||||
|
deptName?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const purchaserList = ref<any[]>([])
|
||||||
|
const assetAdminList = ref<any[]>([])
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
hasContract: '0',
|
||||||
|
contractId: '',
|
||||||
|
isInstallment: '0',
|
||||||
|
totalPhases: 1,
|
||||||
|
supplierName: '',
|
||||||
|
supplierContact: '',
|
||||||
|
purchaserId: '',
|
||||||
|
purchaserName: '',
|
||||||
|
assetAdminId: '',
|
||||||
|
assetAdminName: '',
|
||||||
|
...props.modelValue,
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.modelValue, (val) => {
|
||||||
|
Object.assign(form, val || {})
|
||||||
|
// 人员选择回显
|
||||||
|
if (form.purchaserId && form.purchaserName) {
|
||||||
|
purchaserList.value = [{ id: form.purchaserId, name: form.purchaserName, type: 'user' }]
|
||||||
|
} else {
|
||||||
|
purchaserList.value = []
|
||||||
|
}
|
||||||
|
if (form.assetAdminId && form.assetAdminName) {
|
||||||
|
assetAdminList.value = [{ id: form.assetAdminId, name: form.assetAdminName, type: 'user' }]
|
||||||
|
} else {
|
||||||
|
assetAdminList.value = []
|
||||||
|
}
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
||||||
|
|
||||||
|
const onPurchaserChange = (list: any[]) => {
|
||||||
|
if (list?.length) {
|
||||||
|
const u = list[0]
|
||||||
|
form.purchaserId = u.userId || u.id || ''
|
||||||
|
form.purchaserName = u.name || u.realName || ''
|
||||||
|
} else {
|
||||||
|
form.purchaserId = ''
|
||||||
|
form.purchaserName = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAssetAdminChange = (list: any[]) => {
|
||||||
|
if (list?.length) {
|
||||||
|
const u = list[0]
|
||||||
|
form.assetAdminId = u.userId || u.id || ''
|
||||||
|
form.assetAdminName = u.name || u.realName || ''
|
||||||
|
} else {
|
||||||
|
form.assetAdminId = ''
|
||||||
|
form.assetAdminName = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules: FormRules = {
|
||||||
|
isInstallment: [{ required: true, message: '请选择是否分期验收', trigger: 'change' }],
|
||||||
|
totalPhases: [{ required: true, message: '请输入分期次数', trigger: 'blur' }],
|
||||||
|
}
|
||||||
|
|
||||||
|
const validate = () => formRef.value?.validate()
|
||||||
|
|
||||||
|
defineExpose({ validate, form })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.accept-common-form {
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.accept-common-form :deep(.el-form-item) {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
/* 紧凑表单样式 */
|
||||||
|
.compact-form {
|
||||||
|
:deep(.el-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-form-item__label) {
|
||||||
|
padding-right: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__inner),
|
||||||
|
:deep(.el-textarea__inner) {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,405 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="visible"
|
||||||
|
title="履约验收"
|
||||||
|
width="85%"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
destroy-on-close
|
||||||
|
class="purchasing-accept-modal"
|
||||||
|
@close="handleClose"
|
||||||
|
>
|
||||||
|
<div v-loading="loading" class="modal-body">
|
||||||
|
<div class="main-tabs">
|
||||||
|
<div class="main-tab-nav">
|
||||||
|
<div
|
||||||
|
class="main-tab-item"
|
||||||
|
:class="{ active: mainTab === 'common' }"
|
||||||
|
@click="mainTab = 'common'"
|
||||||
|
>
|
||||||
|
公共信息
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="main-tab-item"
|
||||||
|
:class="{ active: mainTab === 'batch' }"
|
||||||
|
@click="mainTab = 'batch'"
|
||||||
|
>
|
||||||
|
分期验收{{ batches.length > 0 ? ` (${batches.length})` : '' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main-tab-content">
|
||||||
|
<div v-show="mainTab === 'common'" class="tab-content">
|
||||||
|
<AcceptCommonForm
|
||||||
|
ref="commonFormRef"
|
||||||
|
v-model="commonForm"
|
||||||
|
:project-name="applyInfo?.projectName"
|
||||||
|
:dept-name="applyInfo?.deptName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-show="mainTab === 'batch'" class="tab-content">
|
||||||
|
<div v-if="batches.length > 0">
|
||||||
|
<div class="batch-tabs">
|
||||||
|
<div
|
||||||
|
v-for="b in batches"
|
||||||
|
:key="b.id"
|
||||||
|
class="batch-tab-item"
|
||||||
|
:class="{ active: String(b.batch) === activeTab, disabled: !canEditBatch(b.batch) }"
|
||||||
|
@click="canEditBatch(b.batch) && (activeTab = String(b.batch))"
|
||||||
|
>
|
||||||
|
<span>第{{ b.batch }}期</span>
|
||||||
|
<el-tag v-if="isBatchCompleted(b)" type="success" size="small">已填</el-tag>
|
||||||
|
<el-tag v-else-if="!canEditBatch(b.batch)" type="info" size="small">需先完成上一期</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="batch-panel">
|
||||||
|
<AcceptBatchForm
|
||||||
|
v-for="b in batches"
|
||||||
|
v-show="String(b.batch) === activeTab"
|
||||||
|
:key="b.id"
|
||||||
|
v-model="batchForms[b.batch]"
|
||||||
|
:can-fill="canFillForm"
|
||||||
|
:readonly="false"
|
||||||
|
:purchase-id="String(purchaseId)"
|
||||||
|
:acceptance-items="acceptanceItems"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="tip-box">
|
||||||
|
<el-alert type="info" :closable="false" show-icon>
|
||||||
|
请先在「公共信息」中填写并点击「保存公共配置」,系统将按分期次数自动生成验收批次
|
||||||
|
</el-alert>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span>
|
||||||
|
<el-button @click="handleClose">关 闭</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="mainTab === 'common' || batches.length === 0"
|
||||||
|
type="primary"
|
||||||
|
@click="saveCommonConfig"
|
||||||
|
:loading="saving"
|
||||||
|
>
|
||||||
|
保存公共配置
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-else-if="mainTab === 'batch' && activeBatchId"
|
||||||
|
type="primary"
|
||||||
|
@click="saveCurrentBatch"
|
||||||
|
:loading="saving"
|
||||||
|
>
|
||||||
|
保存第{{ activeTab }}期
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, watch, nextTick } from 'vue'
|
||||||
|
import { useMessage } from '/@/hooks/message'
|
||||||
|
import {
|
||||||
|
saveCommonConfig as apiSaveCommonConfig,
|
||||||
|
getCommonConfigWithBatches,
|
||||||
|
updateBatch,
|
||||||
|
canFillForm as apiCanFillForm,
|
||||||
|
getAcceptanceItems,
|
||||||
|
getDetail,
|
||||||
|
} from '/@/api/purchase/purchasingAccept'
|
||||||
|
import AcceptCommonForm from './AcceptCommonForm.vue'
|
||||||
|
import AcceptBatchForm from './AcceptBatchForm.vue'
|
||||||
|
|
||||||
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
const saving = ref(false)
|
||||||
|
const purchaseId = ref<string | number>('')
|
||||||
|
const applyInfo = ref<any>(null)
|
||||||
|
const rowProjectType = ref<string>('A')
|
||||||
|
const canFillForm = ref(true)
|
||||||
|
const acceptanceItems = ref<any[]>([])
|
||||||
|
const batches = ref<any[]>([])
|
||||||
|
const mainTab = ref('common')
|
||||||
|
const activeTab = ref('1')
|
||||||
|
const commonFormRef = ref()
|
||||||
|
const commonForm = reactive<Record<string, any>>({})
|
||||||
|
const batchForms = reactive<Record<number, any>>({})
|
||||||
|
|
||||||
|
const activeBatchId = computed(() => {
|
||||||
|
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
||||||
|
return b?.id || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const canEditBatch = (batch: number) => {
|
||||||
|
if (batch === 1) return true
|
||||||
|
for (let i = 1; i < batch; i++) {
|
||||||
|
if (!isBatchCompletedByIdx(i)) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBatchCompleted = (b: any) => {
|
||||||
|
return !!(b.acceptType && b.acceptDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBatchCompletedByIdx = (batch: number) => {
|
||||||
|
const b = batches.value.find((x: any) => x.batch === batch)
|
||||||
|
return b ? isBatchCompleted(b) : false
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
if (!purchaseId.value) return
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const [configRes, canFillRes] = await Promise.all([
|
||||||
|
getCommonConfigWithBatches(String(purchaseId.value)),
|
||||||
|
apiCanFillForm(String(purchaseId.value)),
|
||||||
|
])
|
||||||
|
const config = configRes?.data
|
||||||
|
canFillForm.value = !!canFillRes?.data
|
||||||
|
|
||||||
|
if (config?.common) {
|
||||||
|
Object.assign(commonForm, {
|
||||||
|
hasContract: config.common.hasContract || '0',
|
||||||
|
contractId: config.common.contractId || '',
|
||||||
|
isInstallment: config.common.isInstallment || '0',
|
||||||
|
totalPhases: config.common.totalPhases || 1,
|
||||||
|
supplierName: config.common.supplierName || '',
|
||||||
|
supplierContact: config.common.supplierContact || '',
|
||||||
|
purchaserId: config.common.purchaserId || '',
|
||||||
|
purchaserName: config.common.purchaserName || '',
|
||||||
|
assetAdminId: config.common.assetAdminId || '',
|
||||||
|
assetAdminName: config.common.assetAdminName || '',
|
||||||
|
})
|
||||||
|
applyInfo.value = config.common
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectType = applyInfo.value?.projectType || rowProjectType.value || 'A'
|
||||||
|
const typeMap: Record<string, string> = { A: 'A', B: 'B', C: 'C' }
|
||||||
|
const at = typeMap[projectType] || 'A'
|
||||||
|
const itemsRes = await getAcceptanceItems(at)
|
||||||
|
acceptanceItems.value = itemsRes?.data || []
|
||||||
|
|
||||||
|
if (config?.batches?.length) {
|
||||||
|
batches.value = config.batches.sort((a: any, b: any) => (a.batch || 0) - (b.batch || 0))
|
||||||
|
activeTab.value = String(batches.value[0]?.batch || '1')
|
||||||
|
mainTab.value = 'batch'
|
||||||
|
for (const b of batches.value) {
|
||||||
|
if (!batchForms[b.batch]) batchForms[b.batch] = {}
|
||||||
|
}
|
||||||
|
await loadBatchDetails()
|
||||||
|
} else {
|
||||||
|
batches.value = []
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
useMessage().error(e?.msg || '加载失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadBatchDetails = async () => {
|
||||||
|
for (const b of batches.value) {
|
||||||
|
try {
|
||||||
|
const res = await getDetail(String(purchaseId.value), b.batch)
|
||||||
|
const d = res?.data
|
||||||
|
if (d?.accept) {
|
||||||
|
const itemMap = (acceptanceItems.value || []).reduce((acc: any, it: any) => {
|
||||||
|
acc[it.id] = it
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
batchForms[b.batch] = {
|
||||||
|
acceptType: d.accept.acceptType || '1',
|
||||||
|
acceptDate: d.accept.acceptDate || '',
|
||||||
|
remark: d.accept.remark || '',
|
||||||
|
templateFileIds: d.accept.templateFileIds || [],
|
||||||
|
acceptContents: (d.contents || []).map((c: any) => {
|
||||||
|
const cfg = itemMap[c.configId]
|
||||||
|
return {
|
||||||
|
configId: c.configId,
|
||||||
|
itemName: cfg?.itemName || '',
|
||||||
|
type: cfg?.type,
|
||||||
|
isQualified: c.isQualified || '1',
|
||||||
|
remark: c.remark || '',
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
acceptTeam: (d.team || []).map((t: any) => ({
|
||||||
|
name: t.name,
|
||||||
|
deptCode: t.deptCode,
|
||||||
|
deptName: t.deptName,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
if (batchForms[b.batch].acceptTeam.length < 3) {
|
||||||
|
while (batchForms[b.batch].acceptTeam.length < 3) {
|
||||||
|
batchForms[b.batch].acceptTeam.push({ name: '', deptCode: '', deptName: '' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (acceptanceItems.value.length && (!batchForms[b.batch].acceptContents || batchForms[b.batch].acceptContents.length === 0)) {
|
||||||
|
batchForms[b.batch].acceptContents = acceptanceItems.value.map((it: any) => ({
|
||||||
|
configId: it.id,
|
||||||
|
itemName: it.itemName,
|
||||||
|
type: it.type,
|
||||||
|
isQualified: '1',
|
||||||
|
remark: '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveCommonConfig = async () => {
|
||||||
|
const valid = await commonFormRef.value?.validate?.().catch(() => false)
|
||||||
|
if (!valid) return
|
||||||
|
if (commonForm.isInstallment === '1' && (!commonForm.totalPhases || commonForm.totalPhases < 1)) {
|
||||||
|
useMessage().error('请填写分期次数')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
saving.value = true
|
||||||
|
try {
|
||||||
|
await apiSaveCommonConfig({
|
||||||
|
purchaseId: String(purchaseId.value),
|
||||||
|
hasContract: commonForm.hasContract,
|
||||||
|
contractId: commonForm.contractId,
|
||||||
|
isInstallment: commonForm.isInstallment,
|
||||||
|
totalPhases: commonForm.isInstallment === '1' ? commonForm.totalPhases : 1,
|
||||||
|
supplierName: commonForm.supplierName,
|
||||||
|
supplierContact: commonForm.supplierContact,
|
||||||
|
purchaserId: commonForm.purchaserId,
|
||||||
|
purchaserName: commonForm.purchaserName,
|
||||||
|
assetAdminId: commonForm.assetAdminId,
|
||||||
|
assetAdminName: commonForm.assetAdminName,
|
||||||
|
})
|
||||||
|
useMessage().success('保存成功')
|
||||||
|
await loadData()
|
||||||
|
} catch (e: any) {
|
||||||
|
useMessage().error(e?.msg || '保存失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveCurrentBatch = async () => {
|
||||||
|
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
||||||
|
if (!b?.id) return
|
||||||
|
const form = batchForms[Number(activeTab.value)]
|
||||||
|
if (!form) return
|
||||||
|
|
||||||
|
const team = (form.acceptTeam || []).filter((m: any) => m?.name)
|
||||||
|
if (team.length < 3 || team.length % 2 === 0) {
|
||||||
|
useMessage().error('验收小组至少3人且为单数')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
saving.value = true
|
||||||
|
try {
|
||||||
|
await updateBatch({
|
||||||
|
id: b.id,
|
||||||
|
purchaseId: String(purchaseId.value),
|
||||||
|
acceptType: form.acceptType,
|
||||||
|
acceptDate: form.acceptDate,
|
||||||
|
remark: form.remark,
|
||||||
|
templateFileIds: form.templateFileIds || [],
|
||||||
|
acceptContents: form.acceptContents || [],
|
||||||
|
acceptTeam: team,
|
||||||
|
})
|
||||||
|
useMessage().success('保存成功')
|
||||||
|
await loadData()
|
||||||
|
} catch (e: any) {
|
||||||
|
useMessage().error(e?.msg || '保存失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false
|
||||||
|
emit('refresh')
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = (row: any) => {
|
||||||
|
purchaseId.value = row?.id ?? ''
|
||||||
|
rowProjectType.value = row?.projectType || 'A'
|
||||||
|
visible.value = true
|
||||||
|
batches.value = []
|
||||||
|
Object.keys(batchForms).forEach((k) => delete batchForms[Number(k)])
|
||||||
|
nextTick(() => loadData())
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal-body {
|
||||||
|
padding: 0;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.main-tab-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
border-bottom: 1px solid var(--el-border-color);
|
||||||
|
}
|
||||||
|
.main-tab-item {
|
||||||
|
padding: 12px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.main-tab-item:hover {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
.main-tab-item.active {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
.main-tab-content {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
.tab-content {
|
||||||
|
min-height: 200px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.tip-box {
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
.batch-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.batch-tab-item {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.batch-tab-item:hover:not(.disabled) {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
.batch-tab-item.active {
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.batch-tab-item.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.batch-panel {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
<span v-else>-</span>
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" fixed="right" width="300">
|
<el-table-column label="操作" align="center" fixed="right" width="360">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
icon="View"
|
icon="View"
|
||||||
@@ -216,6 +216,13 @@
|
|||||||
@click="handleDelete(scope.row)">
|
@click="handleDelete(scope.row)">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
icon="DocumentChecked"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="handleAccept(scope.row)">
|
||||||
|
履约验收
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -258,6 +265,9 @@
|
|||||||
ref="formDialogRef"
|
ref="formDialogRef"
|
||||||
:dict-data="dictData"
|
:dict-data="dictData"
|
||||||
@refresh="getDataList" />
|
@refresh="getDataList" />
|
||||||
|
|
||||||
|
<!-- 履约验收弹窗 -->
|
||||||
|
<PurchasingAcceptModal ref="acceptModalRef" @refresh="getDataList" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -269,10 +279,11 @@ import { getPage, delObj } from "/@/api/finance/purchasingrequisition";
|
|||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
import { getDicts } from '/@/api/admin/dict';
|
import { getDicts } from '/@/api/admin/dict';
|
||||||
import { getTree } from '/@/api/finance/purchasingcategory';
|
import { getTree } from '/@/api/finance/purchasingcategory';
|
||||||
import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning } from '@element-plus/icons-vue'
|
import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning, DocumentChecked } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
|
const PurchasingAcceptModal = defineAsyncComponent(() => import('./accept/PurchasingAcceptModal.vue'));
|
||||||
|
|
||||||
// 字典数据和品目树数据
|
// 字典数据和品目树数据
|
||||||
const dictData = ref({
|
const dictData = ref({
|
||||||
@@ -289,6 +300,7 @@ const dictData = ref({
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
|
const acceptModalRef = ref()
|
||||||
const searchFormRef = ref()
|
const searchFormRef = ref()
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true)
|
||||||
const showAddIframe = ref(false)
|
const showAddIframe = ref(false)
|
||||||
@@ -363,6 +375,7 @@ const handleIframeMessage = (event: MessageEvent) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
<<<<<<< HEAD
|
||||||
* 打开查看对话框
|
* 打开查看对话框
|
||||||
* @param row - 当前行数据
|
* @param row - 当前行数据
|
||||||
*/
|
*/
|
||||||
@@ -376,6 +389,12 @@ const handleView = (row: any) => {
|
|||||||
*/
|
*/
|
||||||
const handleEdit = (row: any) => {
|
const handleEdit = (row: any) => {
|
||||||
formDialogRef.value?.openDialog('edit', row);
|
formDialogRef.value?.openDialog('edit', row);
|
||||||
|
=======
|
||||||
|
* 履约验收
|
||||||
|
*/
|
||||||
|
const handleAccept = (row: any) => {
|
||||||
|
acceptModalRef.value?.open(row);
|
||||||
|
>>>>>>> 61380fa2bca0fe9fd37af1c494a51ba523501f7d
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
116
src/views/professional/common/import-teacher-other-info.vue
Normal file
116
src/views/professional/common/import-teacher-other-info.vue
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="visible" :title="title" width="600" append-to-body>
|
||||||
|
<!-- <el-alert-->
|
||||||
|
<!-- type="warning"-->
|
||||||
|
<!-- :closable="false"-->
|
||||||
|
<!-- show-icon-->
|
||||||
|
<!-- style="margin-bottom: 20px;">-->
|
||||||
|
<!-- <template #title>-->
|
||||||
|
<!-- <span>下载模板</span>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-alert>-->
|
||||||
|
|
||||||
|
<div style="text-align: center; margin-bottom: 20px">
|
||||||
|
<el-button type="success" :icon="Download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-upload
|
||||||
|
class="upload-demo"
|
||||||
|
:action="uploadUrl"
|
||||||
|
:headers="headers"
|
||||||
|
:accept="'.xls,.xlsx'"
|
||||||
|
:on-success="handleUploadSuccess"
|
||||||
|
:on-error="handleAvatarError"
|
||||||
|
:limit="1"
|
||||||
|
drag
|
||||||
|
>
|
||||||
|
<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">只能上传 .xls 或 .xlsx 格式的 Excel 文件</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { ElNotification } from 'element-plus';
|
||||||
|
import { Download, UploadFilled } from '@element-plus/icons-vue';
|
||||||
|
import { Session } from '/@/utils/storage';
|
||||||
|
import { downBlobFile } from '/@/utils/other';
|
||||||
|
|
||||||
|
const title = ref('');
|
||||||
|
// 响应式数据
|
||||||
|
const visible = ref(false);
|
||||||
|
|
||||||
|
// 计算属性
|
||||||
|
const headers = computed(() => {
|
||||||
|
return {
|
||||||
|
Authorization: 'Bearer ' + Session.getToken(),
|
||||||
|
TENANT_ID: Session.getTenant()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadUrl = ref('')
|
||||||
|
const currentType = ref('')
|
||||||
|
const titleMap: Record<string, string> = {
|
||||||
|
titleRelation: '职称信息导入',
|
||||||
|
quaRelation: '职业资格信息导入',
|
||||||
|
cerRelation: '教师资格证信息导入',
|
||||||
|
eduDegree: '学历学位信息导入',
|
||||||
|
partyChange: '党组织变动信息导入',
|
||||||
|
honor: '综合表彰信息导入'
|
||||||
|
}
|
||||||
|
// 方法
|
||||||
|
const init = (type: any) => {
|
||||||
|
currentType.value = type
|
||||||
|
uploadUrl.value = '/professional/file/importTeacherOtherInfo?type=' + type
|
||||||
|
title.value = titleMap[type] || '信息导入'
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'refreshData'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const handleUploadSuccess = () => {
|
||||||
|
visible.value = false;
|
||||||
|
ElNotification({
|
||||||
|
title: '成功',
|
||||||
|
message: '导入成功',
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
|
||||||
|
emit('refreshData')
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAvatarError = (err: any) => {
|
||||||
|
const result = JSON.parse(err.message);
|
||||||
|
if (result.code == '1') {
|
||||||
|
ElNotification.error({
|
||||||
|
title: '错误',
|
||||||
|
message: result.msg,
|
||||||
|
duration: 30000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownloadTemplate = () => {
|
||||||
|
downBlobFile('/professional/file/exportTeacherInfoTemplate', { type: currentType.value || 'titleRelation' }, '职工信息导入模板.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
init,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.upload-demo {
|
||||||
|
:deep(.el-upload-dragger) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -37,6 +37,20 @@
|
|||||||
</template>
|
</template>
|
||||||
</search-form>
|
</search-form>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<el-row>
|
||||||
|
<div class="mb15" style="width: 100%;">
|
||||||
|
<el-button
|
||||||
|
v-auth="'professional_teacherinfo_import'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="UploadFilled"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="handleImportDialog"
|
||||||
|
>导入信息</el-button>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<el-table
|
<el-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
@@ -77,6 +91,9 @@
|
|||||||
@current-change="currentChangeHandle"
|
@current-change="currentChangeHandle"
|
||||||
@size-change="sizeChangeHandle"
|
@size-change="sizeChangeHandle"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 子组件 -->
|
||||||
|
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -88,6 +105,7 @@ import { BasicTableProps, useTable } from '/@/hooks/table'
|
|||||||
import { fetchList } from '/@/api/professional/professionaluser/professionalpartychange'
|
import { fetchList } from '/@/api/professional/professionaluser/professionalpartychange'
|
||||||
|
|
||||||
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
|
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
|
||||||
|
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
|
||||||
|
|
||||||
// 表格引用
|
// 表格引用
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
@@ -100,6 +118,10 @@ const search = reactive({
|
|||||||
realName: ''
|
realName: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 导入加载状态
|
||||||
|
const exportLoading = ref(false)
|
||||||
|
const importTeacherOtherInfoRef = ref()
|
||||||
|
|
||||||
// 配置 useTable
|
// 配置 useTable
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
pageList: async (params: any) => {
|
pageList: async (params: any) => {
|
||||||
@@ -130,6 +152,11 @@ const resetQuery = () => {
|
|||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开导入弹窗
|
||||||
|
const handleImportDialog = () => {
|
||||||
|
importTeacherOtherInfoRef.value?.init('partyChange')
|
||||||
|
}
|
||||||
|
|
||||||
// 表格数据由 useTable(createdIsNeed 默认 true)在挂载时自动请求
|
// 表格数据由 useTable(createdIsNeed 默认 true)在挂载时自动请求
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="page-cards">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="page-wrapper">
|
||||||
<!-- 搜索表单 -->
|
<!-- 筛选卡片 -->
|
||||||
|
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||||
<search-form
|
<search-form
|
||||||
v-show="showSearch"
|
|
||||||
:model="search"
|
:model="search"
|
||||||
ref="searchFormRef"
|
ref="searchFormRef"
|
||||||
@keyup-enter="handleFilter"
|
@keyup-enter="handleFilter"
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="工号" prop="teacherNo">
|
<el-form-item label="工号" prop="teacherNo">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="search.teacherNo"
|
v-model="search.teacherNo"
|
||||||
@@ -32,7 +31,6 @@
|
|||||||
placeholder="请输入工号"
|
placeholder="请输入工号"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="姓名" prop="realName">
|
<el-form-item label="姓名" prop="realName">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="search.realName"
|
v-model="search.realName"
|
||||||
@@ -42,8 +40,6 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleFilter" icon="Search">查询</el-button>
|
<el-button type="primary" @click="handleFilter" icon="Search">查询</el-button>
|
||||||
@@ -51,26 +47,50 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</search-form>
|
</search-form>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
<!-- 列表内容卡片 -->
|
||||||
<el-row>
|
<el-card class="content-card" shadow="never">
|
||||||
<div class="mb15" style="width: 100%;">
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">
|
||||||
|
<el-icon class="title-icon"><Medal /></el-icon>
|
||||||
|
职业资格信息
|
||||||
|
</span>
|
||||||
|
<div class="header-actions">
|
||||||
|
<div class="action-group">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="hasAuth('professional_professionalqualificationrelation_add')"
|
v-if="hasAuth('professional_professionalqualificationrelation_add')"
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="FolderAdd"
|
icon="FolderAdd"
|
||||||
@click="handleAdd">新 增
|
@click="handleAdd"
|
||||||
</el-button>
|
>新增</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="hasAuth('professional_teacherbase_export')"
|
v-if="hasAuth('professional_teacherbase_export')"
|
||||||
type="warning"
|
type="warning"
|
||||||
plain
|
plain
|
||||||
icon="Download"
|
icon="Download"
|
||||||
@click="handleDownLoadWord"
|
@click="handleDownLoadWord"
|
||||||
:loading="exportLoading">导出信息
|
:loading="exportLoading"
|
||||||
</el-button>
|
>导出信息</el-button>
|
||||||
|
<el-button
|
||||||
|
v-auth="'professional_teacherinfo_import'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="UploadFilled"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="handleImportDialog"
|
||||||
|
>导入信息</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
<div class="header-right">
|
||||||
|
<RightToolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<el-table
|
<el-table
|
||||||
@@ -79,6 +99,7 @@
|
|||||||
row-key="id"
|
row-key="id"
|
||||||
v-loading="state.loading"
|
v-loading="state.loading"
|
||||||
border
|
border
|
||||||
|
stripe
|
||||||
:cell-style="tableStyle.cellStyle"
|
:cell-style="tableStyle.cellStyle"
|
||||||
:header-cell-style="tableStyle.headerCellStyle"
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
>
|
>
|
||||||
@@ -180,6 +201,8 @@
|
|||||||
@current-change="currentChangeHandle"
|
@current-change="currentChangeHandle"
|
||||||
@size-change="sizeChangeHandle"
|
@size-change="sizeChangeHandle"
|
||||||
/>
|
/>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 材料预览:图片直接显示,PDF 在组件内部 dialog 中显示 -->
|
<!-- 材料预览:图片直接显示,PDF 在组件内部 dialog 中显示 -->
|
||||||
<preview-file
|
<preview-file
|
||||||
@@ -192,7 +215,7 @@
|
|||||||
<!-- 子组件 -->
|
<!-- 子组件 -->
|
||||||
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
||||||
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
||||||
</div>
|
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -213,11 +236,14 @@ import { getLevelList } from '/@/api/professional/rsbase/professionalqualificati
|
|||||||
import { getWorkTypeList } from '/@/api/professional/rsbase/professionalworktype'
|
import { getWorkTypeList } from '/@/api/professional/rsbase/professionalworktype'
|
||||||
import { PROFESSIONAL_AUDIT_STATE_OPTIONS } from '/@/config/global'
|
import { PROFESSIONAL_AUDIT_STATE_OPTIONS } from '/@/config/global'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
import { Medal } from '@element-plus/icons-vue'
|
||||||
|
const RightToolbar = defineAsyncComponent(() => import('/@/components/RightToolbar/index.vue'))
|
||||||
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
|
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
|
||||||
const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/index.vue'))
|
const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/index.vue'))
|
||||||
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
||||||
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
||||||
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
||||||
|
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
|
||||||
|
|
||||||
// 审核状态选项
|
// 审核状态选项
|
||||||
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
|
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
|
||||||
@@ -249,8 +275,9 @@ const search = reactive({
|
|||||||
// 材料预览
|
// 材料预览
|
||||||
const imgUrl = ref<Array<{ title: string; url: string }>>([])
|
const imgUrl = ref<Array<{ title: string; url: string }>>([])
|
||||||
|
|
||||||
// 导出加载状态
|
// 导出/导入加载状态
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
|
const importTeacherOtherInfoRef = ref()
|
||||||
|
|
||||||
// 资格等级和工种列表
|
// 资格等级和工种列表
|
||||||
const qualificationLevelList = ref<any[]>([])
|
const qualificationLevelList = ref<any[]>([])
|
||||||
@@ -398,6 +425,11 @@ const getWorkTypeName = (id: string | number) => {
|
|||||||
return item ? item.workName : '-'
|
return item ? item.workName : '-'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开导入弹窗
|
||||||
|
const handleImportDialog = () => {
|
||||||
|
importTeacherOtherInfoRef.value?.init('quaRelation')
|
||||||
|
}
|
||||||
|
|
||||||
// 加载字典数据
|
// 加载字典数据
|
||||||
const loadDictData = async () => {
|
const loadDictData = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -424,4 +456,5 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '/@/assets/styles/page-cards.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -69,6 +69,14 @@
|
|||||||
@click="handleDownLoadWord"
|
@click="handleDownLoadWord"
|
||||||
:loading="exportLoading">导出信息
|
:loading="exportLoading">导出信息
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-auth="'professional_teacherinfo_import'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="UploadFilled"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="handleImportDialog">导入信息
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@@ -218,6 +226,7 @@
|
|||||||
<!-- 子组件 -->
|
<!-- 子组件 -->
|
||||||
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
||||||
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
||||||
|
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -245,6 +254,7 @@ const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/i
|
|||||||
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
||||||
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
||||||
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
||||||
|
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
|
||||||
|
|
||||||
// 审核状态选项
|
// 审核状态选项
|
||||||
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
|
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
|
||||||
@@ -279,6 +289,7 @@ const imgUrl = ref<Array<{ title: string; url: string }>>([])
|
|||||||
|
|
||||||
// 导出加载状态
|
// 导出加载状态
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
|
const importTeacherOtherInfoRef = ref()
|
||||||
|
|
||||||
// 学位、学历和教育类型列表
|
// 学位、学历和教育类型列表
|
||||||
const degreeList = ref<any[]>([])
|
const degreeList = ref<any[]>([])
|
||||||
@@ -442,6 +453,11 @@ const getEducationTypeName = (id: string | number | undefined) => {
|
|||||||
return item ? item.name : '-'
|
return item ? item.name : '-'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开导入弹窗
|
||||||
|
const handleImportDialog = () => {
|
||||||
|
importTeacherOtherInfoRef.value?.init('eduDegree')
|
||||||
|
}
|
||||||
|
|
||||||
// 加载字典数据
|
// 加载字典数据
|
||||||
const loadDictData = async () => {
|
const loadDictData = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -69,6 +69,14 @@
|
|||||||
@click="handleDownLoadWord"
|
@click="handleDownLoadWord"
|
||||||
:loading="exportLoading">导出信息
|
:loading="exportLoading">导出信息
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-auth="'professional_teacherinfo_import'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="UploadFilled"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="handleImportDialog">导入信息
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@@ -188,6 +196,7 @@
|
|||||||
<!-- 子组件 -->
|
<!-- 子组件 -->
|
||||||
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
||||||
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
||||||
|
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -213,6 +222,7 @@ const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/i
|
|||||||
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
||||||
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
||||||
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
||||||
|
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
|
||||||
|
|
||||||
// 审核状态选项(独立定义,防止其他页面修改时被波及)
|
// 审核状态选项(独立定义,防止其他页面修改时被波及)
|
||||||
import type { StateOption } from '/@/components/AuditState/index.vue'
|
import type { StateOption } from '/@/components/AuditState/index.vue'
|
||||||
@@ -247,6 +257,7 @@ const imgUrl = ref<Array<{ title: string; url: string }>>([])
|
|||||||
|
|
||||||
// 导出加载状态
|
// 导出加载状态
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
|
const importTeacherOtherInfoRef = ref()
|
||||||
|
|
||||||
// 证书列表
|
// 证书列表
|
||||||
const certificateList = ref<any[]>([])
|
const certificateList = ref<any[]>([])
|
||||||
@@ -385,6 +396,11 @@ const getCertificateName = (id: string | number) => {
|
|||||||
return item ? item.cretificateName : '-'
|
return item ? item.cretificateName : '-'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开导入弹窗
|
||||||
|
const handleImportDialog = () => {
|
||||||
|
importTeacherOtherInfoRef.value?.init('cerRelation')
|
||||||
|
}
|
||||||
|
|
||||||
// 加载字典数据
|
// 加载字典数据
|
||||||
const loadDictData = async () => {
|
const loadDictData = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -68,6 +68,14 @@
|
|||||||
@click="handleDownLoadWord"
|
@click="handleDownLoadWord"
|
||||||
:loading="exportLoading">导出信息
|
:loading="exportLoading">导出信息
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-auth="'professional_teacherinfo_import'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="UploadFilled"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="handleImportDialog">导入信息
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@@ -83,9 +91,45 @@
|
|||||||
>
|
>
|
||||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
|
||||||
<el-table-column prop="state" label="审核状态" width="120" align="center">
|
<el-table-column prop="state" label="审核状态" width="130" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<AuditState :state="scope.row.state" :options="auditStateOptions" />
|
<DetailPopover
|
||||||
|
v-if="scope.row.state === '-2' && scope.row.backReason"
|
||||||
|
title="审核详情"
|
||||||
|
placement="top"
|
||||||
|
:width="300"
|
||||||
|
:items="[
|
||||||
|
{ label: '审核状态', layout: 'horizontal', content: getAuditStateTagConfig(scope.row.state)?.label },
|
||||||
|
{ label: '驳回理由', content: scope.row.backReason, contentClass: 'reason-content' }
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<ClickableTag
|
||||||
|
:type="getAuditStateTagConfig(scope.row.state)?.type || 'danger'"
|
||||||
|
:left-icon="getAuditStateTagConfig(scope.row.state)?.leftIcon"
|
||||||
|
:effect="getAuditStateTagConfig(scope.row.state)?.effect || 'dark'"
|
||||||
|
>
|
||||||
|
{{ getAuditStateTagConfig(scope.row.state)?.label || '已驳回' }}
|
||||||
|
</ClickableTag>
|
||||||
|
</template>
|
||||||
|
<template #content-0>
|
||||||
|
<ClickableTag
|
||||||
|
:type="getAuditStateTagConfig(scope.row.state)?.type || 'danger'"
|
||||||
|
:left-icon="getAuditStateTagConfig(scope.row.state)?.leftIcon"
|
||||||
|
:effect="getAuditStateTagConfig(scope.row.state)?.effect || 'dark'"
|
||||||
|
:right-icon="null"
|
||||||
|
>
|
||||||
|
{{ getAuditStateTagConfig(scope.row.state)?.label || '已驳回' }}
|
||||||
|
</ClickableTag>
|
||||||
|
</template>
|
||||||
|
<template #content-1>
|
||||||
|
<div class="reason-content">
|
||||||
|
<el-icon class="reason-icon"><Warning /></el-icon>
|
||||||
|
<span>{{ scope.row.backReason }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</DetailPopover>
|
||||||
|
<AuditState v-else :state="scope.row.state" :options="auditStateOptions" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
@@ -114,8 +158,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="backReason" label="驳回理由" min-width="150" align="center" show-overflow-tooltip />
|
|
||||||
|
|
||||||
<el-table-column label="操作" width="280" align="center" fixed="right">
|
<el-table-column label="操作" width="280" align="center" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
@@ -158,7 +200,6 @@
|
|||||||
type="danger"
|
type="danger"
|
||||||
link
|
link
|
||||||
icon="delete"
|
icon="delete"
|
||||||
style="margin-left: 12px"
|
|
||||||
@click="handleDel(scope.row)">删除
|
@click="handleDel(scope.row)">删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -183,6 +224,7 @@
|
|||||||
<!-- 子组件 -->
|
<!-- 子组件 -->
|
||||||
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
||||||
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
||||||
|
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -199,13 +241,16 @@ import {
|
|||||||
examObj,
|
examObj,
|
||||||
delObj
|
delObj
|
||||||
} from '/@/api/professional/professionaluser/professionalteacherhonor'
|
} from '/@/api/professional/professionaluser/professionalteacherhonor'
|
||||||
import { PROFESSIONAL_AUDIT_STATE_OPTIONS } from '/@/config/global'
|
import { PROFESSIONAL_AUDIT_STATE_OPTIONS, getStatusConfig } from '/@/config/global'
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
|
const TeacherNameNo = defineAsyncComponent(() => import('/@/components/TeacherNameNo/index.vue'))
|
||||||
const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/index.vue'))
|
const AuditState = defineAsyncComponent(() => import('/@/components/AuditState/index.vue'))
|
||||||
|
const ClickableTag = defineAsyncComponent(() => import('/@/components/ClickableTag/index.vue'))
|
||||||
|
const DetailPopover = defineAsyncComponent(() => import('/@/components/DetailPopover/index.vue'))
|
||||||
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
||||||
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
||||||
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
||||||
|
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
|
||||||
|
|
||||||
// 消息提示 hooks
|
// 消息提示 hooks
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
@@ -217,6 +262,13 @@ const { professional_state: professionalState } = useDict('professional_state')
|
|||||||
// 审核状态选项
|
// 审核状态选项
|
||||||
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
|
const auditStateOptions = PROFESSIONAL_AUDIT_STATE_OPTIONS
|
||||||
|
|
||||||
|
// 审核状态转 ClickableTag 配置(用 options 的 icon 字符串,与 AuditState 一致为实心)
|
||||||
|
const getAuditStateTagConfig = (state: string | number) => {
|
||||||
|
const opt = getStatusConfig(auditStateOptions, state)
|
||||||
|
if (!opt) return null
|
||||||
|
return { type: opt.type, label: opt.label, leftIcon: opt.icon, effect: opt.effect || 'dark' }
|
||||||
|
}
|
||||||
|
|
||||||
// 无权限即无节点
|
// 无权限即无节点
|
||||||
const { hasAuth } = useAuth()
|
const { hasAuth } = useAuth()
|
||||||
|
|
||||||
@@ -239,6 +291,7 @@ const imgUrl = ref<Array<{ title: string; url: string }>>([])
|
|||||||
|
|
||||||
// 导出加载状态
|
// 导出加载状态
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
|
const importTeacherOtherInfoRef = ref()
|
||||||
|
|
||||||
// 配置 useTable
|
// 配置 useTable
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
@@ -365,8 +418,38 @@ const handleDownLoadWord = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开导入弹窗
|
||||||
|
const handleImportDialog = () => {
|
||||||
|
importTeacherOtherInfoRef.value?.init('honor')
|
||||||
|
}
|
||||||
|
|
||||||
// 表格数据由 useTable(createdIsNeed 默认 true)在挂载时自动请求
|
// 表格数据由 useTable(createdIsNeed 默认 true)在挂载时自动请求
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
/* 驳回理由展示(与 backSchoolCheckin 一致) */
|
||||||
|
.reason-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background-color: #fef0f0;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 3px solid #f56c6c;
|
||||||
|
|
||||||
|
.reason-icon {
|
||||||
|
color: #f56c6c;
|
||||||
|
font-size: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #f56c6c;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
word-break: break-all;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,41 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="titlerelation-page">
|
<div class="titlerelation-page">
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<!-- 方案 F:最上标题+右侧按钮,下方搜索,再下方表格 -->
|
<!-- 内容区:最上搜索,其次标题+按钮,再下方表格 -->
|
||||||
<div class="content-block">
|
<div class="content-block">
|
||||||
<!-- 最上:左侧图标+标题,右侧所有按钮 -->
|
<!-- 最上:搜索区 -->
|
||||||
<div class="content-block__header">
|
|
||||||
<span class="card-title">
|
|
||||||
<el-icon class="title-icon"><Document /></el-icon>
|
|
||||||
职称关系
|
|
||||||
</span>
|
|
||||||
<div class="header-actions">
|
|
||||||
<div class="action-group">
|
|
||||||
<el-button
|
|
||||||
v-if="hasAuth('professional_professionaltitlerelation_add')"
|
|
||||||
type="primary"
|
|
||||||
icon="FolderAdd"
|
|
||||||
@click="handleAdd"
|
|
||||||
>新增</el-button>
|
|
||||||
<el-button
|
|
||||||
v-if="hasAuth('professional_teacherbase_export')"
|
|
||||||
type="warning"
|
|
||||||
plain
|
|
||||||
icon="Download"
|
|
||||||
@click="handleDownLoadWord"
|
|
||||||
:loading="exportLoading"
|
|
||||||
>导出信息</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="header-right">
|
|
||||||
<RightToolbar
|
|
||||||
v-model:showSearch="showSearch"
|
|
||||||
@queryTable="getDataList"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 下方:搜索区,方案 F 默认收起 -->
|
|
||||||
<div v-show="showSearch" class="content-block__filter">
|
<div v-show="showSearch" class="content-block__filter">
|
||||||
<search-form
|
<search-form
|
||||||
:model="search"
|
:model="search"
|
||||||
@@ -118,6 +86,42 @@
|
|||||||
</search-form>
|
</search-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 其次:左侧按钮,右侧 RightToolbar -->
|
||||||
|
<div class="content-block__header">
|
||||||
|
<div class="header-actions">
|
||||||
|
<div class="action-group">
|
||||||
|
<el-button
|
||||||
|
v-if="hasAuth('professional_professionaltitlerelation_add')"
|
||||||
|
type="primary"
|
||||||
|
icon="FolderAdd"
|
||||||
|
@click="handleAdd"
|
||||||
|
>新增</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="hasAuth('professional_teacherbase_export')"
|
||||||
|
type="warning"
|
||||||
|
plain
|
||||||
|
icon="Download"
|
||||||
|
@click="handleDownLoadWord"
|
||||||
|
:loading="exportLoading"
|
||||||
|
>导出信息</el-button>
|
||||||
|
<el-button
|
||||||
|
v-auth="'professional_teacherinfo_import'"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="UploadFilled"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="handleImportDialog">导入信息
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<RightToolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 再下方:表格 -->
|
<!-- 再下方:表格 -->
|
||||||
<el-table
|
<el-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
@@ -242,12 +246,13 @@
|
|||||||
<MultiDialog ref="multiDialogRef" @getList="getDataList" :page="state.pagination" :nowRow="null" />
|
<MultiDialog ref="multiDialogRef" @getList="getDataList" :page="state.pagination" :nowRow="null" />
|
||||||
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
<DataForm ref="dataFormRef" @refreshData="handleFilter" />
|
||||||
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
<ProfessionalBackResaon ref="backReasonRef" @refreshData="handleFilter" />
|
||||||
|
|
||||||
|
<import-teacher-other-info ref="importTeacherOtherInfoRef" @refreshData="handleFilter"></import-teacher-other-info>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, nextTick } from 'vue'
|
import { ref, reactive, onMounted, nextTick } from 'vue'
|
||||||
import { Document } from '@element-plus/icons-vue'
|
|
||||||
import { BasicTableProps, useTable } from '/@/hooks/table'
|
import { BasicTableProps, useTable } from '/@/hooks/table'
|
||||||
import { useAuth } from '/@/hooks/auth'
|
import { useAuth } from '/@/hooks/auth'
|
||||||
import { useMessage } from '/@/hooks/message'
|
import { useMessage } from '/@/hooks/message'
|
||||||
@@ -270,6 +275,7 @@ const MultiDialog = defineAsyncComponent(() => import('/@/views/professional/tea
|
|||||||
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
const DataForm = defineAsyncComponent(() => import('./form.vue'))
|
||||||
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
const ProfessionalBackResaon = defineAsyncComponent(() => import('/@/views/professional/common/professional-back-resaon.vue'))
|
||||||
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
const previewFile = defineAsyncComponent(() => import('/@/components/tools/preview-file.vue'))
|
||||||
|
const ImportTeacherOtherInfo = defineAsyncComponent(() => import('/@/views/professional/common/import-teacher-other-info.vue'))
|
||||||
|
|
||||||
// 无权限即无节点:使用 useAuth + v-if
|
// 无权限即无节点:使用 useAuth + v-if
|
||||||
const { hasAuth } = useAuth()
|
const { hasAuth } = useAuth()
|
||||||
@@ -467,6 +473,11 @@ const loadDictData = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const importTeacherOtherInfoRef=ref()
|
||||||
|
const handleImportDialog = () => {
|
||||||
|
importTeacherOtherInfoRef.value?.init('titleRelation')
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化:仅加载下拉字典,表格数据由 useTable 在 createdIsNeed: true 时自动请求
|
// 初始化:仅加载下拉字典,表格数据由 useTable 在 createdIsNeed: true 时自动请求
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadDictData()
|
await loadDictData()
|
||||||
@@ -486,10 +497,10 @@ onMounted(async () => {
|
|||||||
gap: 0;
|
gap: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 筛选:方案 F,内容区内置筛选区,默认收起 */
|
/* 筛选:内容区最上方,无上外边距;与下方标题栏间距用 margin-bottom */
|
||||||
.content-block__filter {
|
.content-block__filter {
|
||||||
padding: 16px 20px 5px 20px;
|
padding: 16px 20px 5px 20px;
|
||||||
margin-top: 12px;
|
margin-top: 0;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
background: var(--el-fill-color-light);
|
background: var(--el-fill-color-light);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -535,21 +546,25 @@ onMounted(async () => {
|
|||||||
.header-actions {
|
.header-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 按钮间距按规范 10px;与 RightToolbar 区隔 */
|
||||||
.action-group {
|
.action-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-right {
|
.header-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
padding-left: 12px;
|
||||||
|
// border-left: 1px solid var(--el-border-color-lighter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表格 */
|
/* 表格 */
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ import { ElNotification } from 'element-plus';
|
|||||||
import { Download } from '@element-plus/icons-vue';
|
import { Download } from '@element-plus/icons-vue';
|
||||||
import global from '/@/components/tools/commondict.vue';
|
import global from '/@/components/tools/commondict.vue';
|
||||||
import request from '/@/utils/request';
|
import request from '/@/utils/request';
|
||||||
import { exportTeacherInfoBySelf } from '/@/api/professional/professionalfile';
|
import { makeExportTeacherInfoBySelfTask } from '/@/api/professional/professionalfile';
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -224,7 +224,7 @@ const exportTeacherInfo = async () => {
|
|||||||
teacherBaseDTO: searchData,
|
teacherBaseDTO: searchData,
|
||||||
};
|
};
|
||||||
|
|
||||||
exportTeacherInfoBySelf(params).then((res:any)=>{
|
makeExportTeacherInfoBySelfTask(params).then((res:any)=>{
|
||||||
ElNotification.success({
|
ElNotification.success({
|
||||||
title: '下载后台进行中',
|
title: '下载后台进行中',
|
||||||
message: '操作成功'
|
message: '操作成功'
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<el-upload
|
<el-upload
|
||||||
class="upload-demo"
|
class="upload-demo"
|
||||||
action="/professional/file/importTeacherInfoSimple"
|
action="/professional/file/makeImportTeacherInfoSimpleTask"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:accept="'.xls,.xlsx'"
|
:accept="'.xls,.xlsx'"
|
||||||
:on-success="handleUploadSuccess"
|
:on-success="handleUploadSuccess"
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="teacherbase-page">
|
<div class="page-cards">
|
||||||
<div class="page-wrapper">
|
<div class="page-wrapper">
|
||||||
<!-- 筛选条件卡片:标题由 SearchForm 组件内置 -->
|
<!-- 筛选条件卡片:标题由 SearchForm 组件内置 -->
|
||||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||||
<search-form
|
<search-form
|
||||||
:model="search"
|
:model="search"
|
||||||
ref="searchFormRef"
|
ref="searchFormRef"
|
||||||
filter-title="筛选"
|
|
||||||
@keyup-enter="handleFilter(search)"
|
@keyup-enter="handleFilter(search)"
|
||||||
>
|
>
|
||||||
<template #default="{ visible }">
|
<template #default="{ visible }">
|
||||||
@@ -215,14 +214,14 @@
|
|||||||
icon="Lock"
|
icon="Lock"
|
||||||
@click="dialogVisible.statusDialogFormVisible=true">状态锁定
|
@click="dialogVisible.statusDialogFormVisible=true">状态锁定
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<!-- <el-button-->
|
||||||
v-if="permissions.professional_teacherbase_export"
|
<!-- v-if="permissions.professional_teacherbase_export"-->
|
||||||
type="warning"
|
<!-- type="warning"-->
|
||||||
plain
|
<!-- plain-->
|
||||||
icon="Download"
|
<!-- icon="Download"-->
|
||||||
:loading="exportLoading"
|
<!-- :loading="exportLoading"-->
|
||||||
@click="handleDownLoadWord('')">导出WORD
|
<!-- @click="handleDownLoadWord('')">导出WORD-->
|
||||||
</el-button>
|
<!-- </el-button>-->
|
||||||
<el-button
|
<el-button
|
||||||
v-if="permissions.professional_teacherbase_export"
|
v-if="permissions.professional_teacherbase_export"
|
||||||
type="warning"
|
type="warning"
|
||||||
@@ -2698,96 +2697,7 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
// 页面整体布局
|
@import '/@/assets/styles/page-cards.scss';
|
||||||
.teacherbase-page {
|
|
||||||
padding: 12px;
|
|
||||||
min-height: 100%;
|
|
||||||
background: var(--el-bg-color-page, #f5f6f8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 筛选卡片(标题栏与表单样式在 SearchForm 组件内)
|
|
||||||
.search-card {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid var(--el-border-color-lighter);
|
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
||||||
background: var(--el-bg-color);
|
|
||||||
|
|
||||||
:deep(.el-card__body) {
|
|
||||||
padding: 18px 20px 5px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列表内容卡片
|
|
||||||
.content-card {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid var(--el-border-color-lighter);
|
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
||||||
background: var(--el-bg-color);
|
|
||||||
|
|
||||||
:deep(.el-card__header) {
|
|
||||||
padding: 20px 20px 15px;
|
|
||||||
border-bottom: 1px solid var(--el-border-color-lighter);
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-card__body) {
|
|
||||||
padding: 15px 20px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
|
|
||||||
.title-icon {
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-group {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主表格行高稍增加
|
|
||||||
.teacherbase-table {
|
|
||||||
:deep(.el-table__body td),
|
|
||||||
:deep(.el-table__header th) {
|
|
||||||
padding: 9px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 列表内链接与占位(主表格与弹窗内通用)
|
// 列表内链接与占位(主表格与弹窗内通用)
|
||||||
:deep(.certificate-link) {
|
:deep(.certificate-link) {
|
||||||
|
|||||||
136
src/views/purchase/acceptanceItemConfig/form.vue
Normal file
136
src/views/purchase/acceptanceItemConfig/form.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||||
|
:close-on-click-modal="false" draggable>
|
||||||
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="remark" prop="remark">
|
||||||
|
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="关联验收类型:A:货物 B:工程 C:服务" prop="acceptanceType">
|
||||||
|
<el-input v-model="form.acceptanceType" placeholder="请输入关联验收类型:A:货物 B:工程 C:服务"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="验收项名称" prop="itemName">
|
||||||
|
<el-input v-model="form.itemName" placeholder="请输入验收项名称"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="是否启用 0:不启用 1:启用" prop="isEnabled">
|
||||||
|
<el-input v-model="form.isEnabled" placeholder="请输入是否启用 0:不启用 1:启用"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="排序" prop="sortOrder">
|
||||||
|
<el-input v-model="form.sortOrder" placeholder="请输入排序"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="AcceptanceItemConfigDialog">
|
||||||
|
// ========== 1. 导入语句 ==========
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
import { rule } from '/@/utils/validate';
|
||||||
|
import { useMessage } from "/@/hooks/message";
|
||||||
|
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/acceptanceItemConfig';
|
||||||
|
|
||||||
|
// ========== 2. 组件定义 ==========
|
||||||
|
// 定义组件事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
|
// ========== 3. 响应式数据定义 ==========
|
||||||
|
// 基础响应式变量
|
||||||
|
const dataFormRef = ref(); // 表单引用
|
||||||
|
const visible = ref(false); // 弹窗显示状态
|
||||||
|
const loading = ref(false); // 加载状态
|
||||||
|
|
||||||
|
// 表单数据对象
|
||||||
|
const form = reactive({
|
||||||
|
id: '', // 主键
|
||||||
|
remark: '', // ${field.fieldComment}
|
||||||
|
acceptanceType: '', // 关联验收类型:A:货物 B:工程 C:服务
|
||||||
|
itemName: '', // 验收项名称
|
||||||
|
isEnabled: '', // 是否启用 0:不启用 1:启用
|
||||||
|
sortOrder: '', // 排序
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 4. 字典数据处理 ==========
|
||||||
|
|
||||||
|
// ========== 5. 表单校验规则 ==========
|
||||||
|
const dataRules = ref({
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 6. 方法定义 ==========
|
||||||
|
// 获取详情数据
|
||||||
|
const getAcceptanceItemConfigData = async (id: string) => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const { data } = await getObj({ id: id });
|
||||||
|
// 直接将第一条数据赋值给表单
|
||||||
|
Object.assign(form, data[0]);
|
||||||
|
} catch (error) {
|
||||||
|
useMessage().error('获取数据失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹窗方法
|
||||||
|
const openDialog = (id: string) => {
|
||||||
|
visible.value = true;
|
||||||
|
form.id = '';
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
|
nextTick(() => {
|
||||||
|
dataFormRef.value?.resetFields();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取AcceptanceItemConfig信息
|
||||||
|
if (id) {
|
||||||
|
form.id = id;
|
||||||
|
getAcceptanceItemConfigData(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单方法
|
||||||
|
const onSubmit = async () => {
|
||||||
|
loading.value = true; // 防止重复提交
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||||
|
if (!valid) {
|
||||||
|
loading.value = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 根据是否有ID判断是新增还是修改
|
||||||
|
form.id ? await putObj(form) : await addObj(form);
|
||||||
|
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||||
|
visible.value = false;
|
||||||
|
emit('refresh'); // 通知父组件刷新列表
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== 7. 对外暴露 ==========
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
openDialog
|
||||||
|
});
|
||||||
|
</script>
|
||||||
223
src/views/purchase/acceptanceItemConfig/index.vue
Normal file
223
src/views/purchase/acceptanceItemConfig/index.vue
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-padding">
|
||||||
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
|
|
||||||
|
<!-- 操作按钮区域 -->
|
||||||
|
<el-row>
|
||||||
|
<div class="mb8" style="width: 100%">
|
||||||
|
<el-button
|
||||||
|
icon="folder-add"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="formDialogRef.openDialog()"
|
||||||
|
v-auth="'purchase_acceptanceItemConfig_add'"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
icon="upload-filled"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="excelUploadRef.show()"
|
||||||
|
v-auth="'purchase_acceptanceItemConfig_add'"
|
||||||
|
>
|
||||||
|
导入
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
:disabled="multiple"
|
||||||
|
icon="Delete"
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_acceptanceItemConfig_del'"
|
||||||
|
@click="handleDelete(selectObjs)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'purchase_acceptanceItemConfig_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right;"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 数据表格区域 -->
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
|
@selection-change="selectionChangHandle"
|
||||||
|
@sort-change="sortChangeHandle"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
|
<el-table-column type="index" label="#" width="40" />
|
||||||
|
<el-table-column
|
||||||
|
prop="remark"
|
||||||
|
label="remark"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="acceptanceType"
|
||||||
|
label="关联验收类型:A:货物 B:工程 C:服务"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="itemName"
|
||||||
|
label="验收项名称"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="isEnabled"
|
||||||
|
label="是否启用 0:不启用 1:启用"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="sortOrder"
|
||||||
|
label="排序"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_acceptanceItemConfig_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
icon="delete"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_acceptanceItemConfig_del'"
|
||||||
|
@click="handleDelete([scope.row.id])"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination
|
||||||
|
@size-change="sizeChangeHandle"
|
||||||
|
@current-change="currentChangeHandle"
|
||||||
|
v-bind="state.pagination"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑、新增弹窗 -->
|
||||||
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
|
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||||
|
<upload-excel
|
||||||
|
ref="excelUploadRef"
|
||||||
|
title="导入"
|
||||||
|
url="/purchase/acceptanceItemConfig/import"
|
||||||
|
temp-url="/admin/sys-file/local/file/acceptanceItemConfig.xlsx"
|
||||||
|
@refreshDataList="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="systemAcceptanceItemConfig">
|
||||||
|
// ========== 导入声明 ==========
|
||||||
|
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||||
|
import { fetchList, delObjs } from "/@/api/purchase/acceptanceItemConfig";
|
||||||
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
|
||||||
|
// ========== 组件声明 ==========
|
||||||
|
// 异步加载表单弹窗组件
|
||||||
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
|
|
||||||
|
// ========== 字典数据 ==========
|
||||||
|
|
||||||
|
// ========== 组件引用 ==========
|
||||||
|
const formDialogRef = ref(); // 表单弹窗引用
|
||||||
|
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||||
|
const queryRef = ref(); // 查询表单引用
|
||||||
|
|
||||||
|
// ========== 响应式数据 ==========
|
||||||
|
const showSearch = ref(true); // 是否显示搜索区域
|
||||||
|
const selectObjs = ref([]) as any; // 表格多选数据
|
||||||
|
const multiple = ref(true); // 是否多选
|
||||||
|
|
||||||
|
// ========== 表格状态 ==========
|
||||||
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
|
queryForm: {}, // 查询参数
|
||||||
|
pageList: fetchList // 分页查询方法
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== Hook引用 ==========
|
||||||
|
// 表格相关Hook
|
||||||
|
const {
|
||||||
|
getDataList,
|
||||||
|
currentChangeHandle,
|
||||||
|
sizeChangeHandle,
|
||||||
|
sortChangeHandle,
|
||||||
|
downBlobFile,
|
||||||
|
tableStyle
|
||||||
|
} = useTable(state);
|
||||||
|
|
||||||
|
// ========== 方法定义 ==========
|
||||||
|
/**
|
||||||
|
* 重置查询条件
|
||||||
|
*/
|
||||||
|
const resetQuery = () => {
|
||||||
|
// 清空搜索条件
|
||||||
|
queryRef.value?.resetFields();
|
||||||
|
// 清空多选
|
||||||
|
selectObjs.value = [];
|
||||||
|
// 重新查询
|
||||||
|
getDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel文件
|
||||||
|
*/
|
||||||
|
const exportExcel = () => {
|
||||||
|
downBlobFile(
|
||||||
|
'/purchase/acceptanceItemConfig/export',
|
||||||
|
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||||
|
'acceptanceItemConfig.xlsx'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格多选事件处理
|
||||||
|
* @param objs 选中的数据行
|
||||||
|
*/
|
||||||
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
|
selectObjs.value = objs.map(({ id }) => id);
|
||||||
|
multiple.value = !objs.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据处理
|
||||||
|
* @param ids 要删除的数据ID数组
|
||||||
|
*/
|
||||||
|
const handleDelete = async (ids: string[]) => {
|
||||||
|
try {
|
||||||
|
await useMessageBox().confirm('此操作将永久删除');
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await delObjs(ids);
|
||||||
|
getDataList();
|
||||||
|
useMessage().success('删除成功');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
130
src/views/purchase/puchasingAcceptContent/form.vue
Normal file
130
src/views/purchase/puchasingAcceptContent/form.vue
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||||
|
:close-on-click-modal="false" draggable>
|
||||||
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="remark" prop="remark">
|
||||||
|
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="配置项ID" prop="configId">
|
||||||
|
<el-input v-model="form.configId" placeholder="请输入配置项ID"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="是否合格 0:不合格 1:合格" prop="isQualified">
|
||||||
|
<el-input v-model="form.isQualified" placeholder="请输入是否合格 0:不合格 1:合格"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="验收批次ID" prop="acceptBatchId">
|
||||||
|
<el-input v-model="form.acceptBatchId" placeholder="请输入验收批次ID"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="PuchasingAcceptContentDialog">
|
||||||
|
// ========== 1. 导入语句 ==========
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
import { rule } from '/@/utils/validate';
|
||||||
|
import { useMessage } from "/@/hooks/message";
|
||||||
|
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/puchasingAcceptContent';
|
||||||
|
|
||||||
|
// ========== 2. 组件定义 ==========
|
||||||
|
// 定义组件事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
|
// ========== 3. 响应式数据定义 ==========
|
||||||
|
// 基础响应式变量
|
||||||
|
const dataFormRef = ref(); // 表单引用
|
||||||
|
const visible = ref(false); // 弹窗显示状态
|
||||||
|
const loading = ref(false); // 加载状态
|
||||||
|
|
||||||
|
// 表单数据对象
|
||||||
|
const form = reactive({
|
||||||
|
id: '', // 主键
|
||||||
|
remark: '', // ${field.fieldComment}
|
||||||
|
configId: '', // 配置项ID
|
||||||
|
isQualified: '', // 是否合格 0:不合格 1:合格
|
||||||
|
acceptBatchId: '', // 验收批次ID
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 4. 字典数据处理 ==========
|
||||||
|
|
||||||
|
// ========== 5. 表单校验规则 ==========
|
||||||
|
const dataRules = ref({
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 6. 方法定义 ==========
|
||||||
|
// 获取详情数据
|
||||||
|
const getPuchasingAcceptContentData = async (id: string) => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const { data } = await getObj({ id: id });
|
||||||
|
// 直接将第一条数据赋值给表单
|
||||||
|
Object.assign(form, data[0]);
|
||||||
|
} catch (error) {
|
||||||
|
useMessage().error('获取数据失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹窗方法
|
||||||
|
const openDialog = (id: string) => {
|
||||||
|
visible.value = true;
|
||||||
|
form.id = '';
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
|
nextTick(() => {
|
||||||
|
dataFormRef.value?.resetFields();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取PuchasingAcceptContent信息
|
||||||
|
if (id) {
|
||||||
|
form.id = id;
|
||||||
|
getPuchasingAcceptContentData(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单方法
|
||||||
|
const onSubmit = async () => {
|
||||||
|
loading.value = true; // 防止重复提交
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||||
|
if (!valid) {
|
||||||
|
loading.value = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 根据是否有ID判断是新增还是修改
|
||||||
|
form.id ? await putObj(form) : await addObj(form);
|
||||||
|
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||||
|
visible.value = false;
|
||||||
|
emit('refresh'); // 通知父组件刷新列表
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== 7. 对外暴露 ==========
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
openDialog
|
||||||
|
});
|
||||||
|
</script>
|
||||||
218
src/views/purchase/puchasingAcceptContent/index.vue
Normal file
218
src/views/purchase/puchasingAcceptContent/index.vue
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-padding">
|
||||||
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
|
|
||||||
|
<!-- 操作按钮区域 -->
|
||||||
|
<el-row>
|
||||||
|
<div class="mb8" style="width: 100%">
|
||||||
|
<el-button
|
||||||
|
icon="folder-add"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="formDialogRef.openDialog()"
|
||||||
|
v-auth="'purchase_puchasingAcceptContent_add'"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
icon="upload-filled"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="excelUploadRef.show()"
|
||||||
|
v-auth="'purchase_puchasingAcceptContent_add'"
|
||||||
|
>
|
||||||
|
导入
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
:disabled="multiple"
|
||||||
|
icon="Delete"
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_puchasingAcceptContent_del'"
|
||||||
|
@click="handleDelete(selectObjs)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'purchase_puchasingAcceptContent_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right;"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 数据表格区域 -->
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
|
@selection-change="selectionChangHandle"
|
||||||
|
@sort-change="sortChangeHandle"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
|
<el-table-column type="index" label="#" width="40" />
|
||||||
|
<el-table-column
|
||||||
|
prop="remark"
|
||||||
|
label="remark"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="configId"
|
||||||
|
label="配置项ID"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="isQualified"
|
||||||
|
label="是否合格 0:不合格 1:合格"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="acceptBatchId"
|
||||||
|
label="验收批次ID"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_puchasingAcceptContent_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
icon="delete"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_puchasingAcceptContent_del'"
|
||||||
|
@click="handleDelete([scope.row.id])"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination
|
||||||
|
@size-change="sizeChangeHandle"
|
||||||
|
@current-change="currentChangeHandle"
|
||||||
|
v-bind="state.pagination"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑、新增弹窗 -->
|
||||||
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
|
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||||
|
<upload-excel
|
||||||
|
ref="excelUploadRef"
|
||||||
|
title="导入"
|
||||||
|
url="/purchase/puchasingAcceptContent/import"
|
||||||
|
temp-url="/admin/sys-file/local/file/puchasingAcceptContent.xlsx"
|
||||||
|
@refreshDataList="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="systemPuchasingAcceptContent">
|
||||||
|
// ========== 导入声明 ==========
|
||||||
|
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||||
|
import { fetchList, delObjs } from "/@/api/purchase/puchasingAcceptContent";
|
||||||
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
|
||||||
|
// ========== 组件声明 ==========
|
||||||
|
// 异步加载表单弹窗组件
|
||||||
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
|
|
||||||
|
// ========== 字典数据 ==========
|
||||||
|
|
||||||
|
// ========== 组件引用 ==========
|
||||||
|
const formDialogRef = ref(); // 表单弹窗引用
|
||||||
|
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||||
|
const queryRef = ref(); // 查询表单引用
|
||||||
|
|
||||||
|
// ========== 响应式数据 ==========
|
||||||
|
const showSearch = ref(true); // 是否显示搜索区域
|
||||||
|
const selectObjs = ref([]) as any; // 表格多选数据
|
||||||
|
const multiple = ref(true); // 是否多选
|
||||||
|
|
||||||
|
// ========== 表格状态 ==========
|
||||||
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
|
queryForm: {}, // 查询参数
|
||||||
|
pageList: fetchList // 分页查询方法
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== Hook引用 ==========
|
||||||
|
// 表格相关Hook
|
||||||
|
const {
|
||||||
|
getDataList,
|
||||||
|
currentChangeHandle,
|
||||||
|
sizeChangeHandle,
|
||||||
|
sortChangeHandle,
|
||||||
|
downBlobFile,
|
||||||
|
tableStyle
|
||||||
|
} = useTable(state);
|
||||||
|
|
||||||
|
// ========== 方法定义 ==========
|
||||||
|
/**
|
||||||
|
* 重置查询条件
|
||||||
|
*/
|
||||||
|
const resetQuery = () => {
|
||||||
|
// 清空搜索条件
|
||||||
|
queryRef.value?.resetFields();
|
||||||
|
// 清空多选
|
||||||
|
selectObjs.value = [];
|
||||||
|
// 重新查询
|
||||||
|
getDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel文件
|
||||||
|
*/
|
||||||
|
const exportExcel = () => {
|
||||||
|
downBlobFile(
|
||||||
|
'/purchase/puchasingAcceptContent/export',
|
||||||
|
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||||
|
'puchasingAcceptContent.xlsx'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格多选事件处理
|
||||||
|
* @param objs 选中的数据行
|
||||||
|
*/
|
||||||
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
|
selectObjs.value = objs.map(({ id }) => id);
|
||||||
|
multiple.value = !objs.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据处理
|
||||||
|
* @param ids 要删除的数据ID数组
|
||||||
|
*/
|
||||||
|
const handleDelete = async (ids: string[]) => {
|
||||||
|
try {
|
||||||
|
await useMessageBox().confirm('此操作将永久删除');
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await delObjs(ids);
|
||||||
|
getDataList();
|
||||||
|
useMessage().success('删除成功');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
136
src/views/purchase/puchasingAcceptTeam/form.vue
Normal file
136
src/views/purchase/puchasingAcceptTeam/form.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||||
|
:close-on-click-modal="false" draggable>
|
||||||
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="remark" prop="remark">
|
||||||
|
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="所在部门编码" prop="deptCode">
|
||||||
|
<el-input v-model="form.deptCode" placeholder="请输入所在部门编码"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="所在部门" prop="deptName">
|
||||||
|
<el-input v-model="form.deptName" placeholder="请输入所在部门"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="form.name" placeholder="请输入姓名"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="验收批次ID" prop="acceptBatchId">
|
||||||
|
<el-input v-model="form.acceptBatchId" placeholder="请输入验收批次ID"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="PuchasingAcceptTeamDialog">
|
||||||
|
// ========== 1. 导入语句 ==========
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
import { rule } from '/@/utils/validate';
|
||||||
|
import { useMessage } from "/@/hooks/message";
|
||||||
|
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/puchasingAcceptTeam';
|
||||||
|
|
||||||
|
// ========== 2. 组件定义 ==========
|
||||||
|
// 定义组件事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
|
// ========== 3. 响应式数据定义 ==========
|
||||||
|
// 基础响应式变量
|
||||||
|
const dataFormRef = ref(); // 表单引用
|
||||||
|
const visible = ref(false); // 弹窗显示状态
|
||||||
|
const loading = ref(false); // 加载状态
|
||||||
|
|
||||||
|
// 表单数据对象
|
||||||
|
const form = reactive({
|
||||||
|
id: '', // 主键
|
||||||
|
remark: '', // ${field.fieldComment}
|
||||||
|
deptCode: '', // 所在部门编码
|
||||||
|
deptName: '', // 所在部门
|
||||||
|
name: '', // 姓名
|
||||||
|
acceptBatchId: '', // 验收批次ID
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 4. 字典数据处理 ==========
|
||||||
|
|
||||||
|
// ========== 5. 表单校验规则 ==========
|
||||||
|
const dataRules = ref({
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 6. 方法定义 ==========
|
||||||
|
// 获取详情数据
|
||||||
|
const getPuchasingAcceptTeamData = async (id: string) => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const { data } = await getObj({ id: id });
|
||||||
|
// 直接将第一条数据赋值给表单
|
||||||
|
Object.assign(form, data[0]);
|
||||||
|
} catch (error) {
|
||||||
|
useMessage().error('获取数据失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹窗方法
|
||||||
|
const openDialog = (id: string) => {
|
||||||
|
visible.value = true;
|
||||||
|
form.id = '';
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
|
nextTick(() => {
|
||||||
|
dataFormRef.value?.resetFields();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取PuchasingAcceptTeam信息
|
||||||
|
if (id) {
|
||||||
|
form.id = id;
|
||||||
|
getPuchasingAcceptTeamData(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单方法
|
||||||
|
const onSubmit = async () => {
|
||||||
|
loading.value = true; // 防止重复提交
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||||
|
if (!valid) {
|
||||||
|
loading.value = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 根据是否有ID判断是新增还是修改
|
||||||
|
form.id ? await putObj(form) : await addObj(form);
|
||||||
|
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||||
|
visible.value = false;
|
||||||
|
emit('refresh'); // 通知父组件刷新列表
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== 7. 对外暴露 ==========
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
openDialog
|
||||||
|
});
|
||||||
|
</script>
|
||||||
223
src/views/purchase/puchasingAcceptTeam/index.vue
Normal file
223
src/views/purchase/puchasingAcceptTeam/index.vue
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-padding">
|
||||||
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
|
|
||||||
|
<!-- 操作按钮区域 -->
|
||||||
|
<el-row>
|
||||||
|
<div class="mb8" style="width: 100%">
|
||||||
|
<el-button
|
||||||
|
icon="folder-add"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="formDialogRef.openDialog()"
|
||||||
|
v-auth="'purchase_puchasingAcceptTeam_add'"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
icon="upload-filled"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="excelUploadRef.show()"
|
||||||
|
v-auth="'purchase_puchasingAcceptTeam_add'"
|
||||||
|
>
|
||||||
|
导入
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
:disabled="multiple"
|
||||||
|
icon="Delete"
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_puchasingAcceptTeam_del'"
|
||||||
|
@click="handleDelete(selectObjs)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'purchase_puchasingAcceptTeam_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right;"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 数据表格区域 -->
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
|
@selection-change="selectionChangHandle"
|
||||||
|
@sort-change="sortChangeHandle"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
|
<el-table-column type="index" label="#" width="40" />
|
||||||
|
<el-table-column
|
||||||
|
prop="remark"
|
||||||
|
label="remark"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="deptCode"
|
||||||
|
label="所在部门编码"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="deptName"
|
||||||
|
label="所在部门"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
label="姓名"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="acceptBatchId"
|
||||||
|
label="验收批次ID"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_puchasingAcceptTeam_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
icon="delete"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_puchasingAcceptTeam_del'"
|
||||||
|
@click="handleDelete([scope.row.id])"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination
|
||||||
|
@size-change="sizeChangeHandle"
|
||||||
|
@current-change="currentChangeHandle"
|
||||||
|
v-bind="state.pagination"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑、新增弹窗 -->
|
||||||
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
|
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||||
|
<upload-excel
|
||||||
|
ref="excelUploadRef"
|
||||||
|
title="导入"
|
||||||
|
url="/purchase/puchasingAcceptTeam/import"
|
||||||
|
temp-url="/admin/sys-file/local/file/puchasingAcceptTeam.xlsx"
|
||||||
|
@refreshDataList="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="systemPuchasingAcceptTeam">
|
||||||
|
// ========== 导入声明 ==========
|
||||||
|
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||||
|
import { fetchList, delObjs } from "/@/api/purchase/puchasingAcceptTeam";
|
||||||
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
|
||||||
|
// ========== 组件声明 ==========
|
||||||
|
// 异步加载表单弹窗组件
|
||||||
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
|
|
||||||
|
// ========== 字典数据 ==========
|
||||||
|
|
||||||
|
// ========== 组件引用 ==========
|
||||||
|
const formDialogRef = ref(); // 表单弹窗引用
|
||||||
|
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||||
|
const queryRef = ref(); // 查询表单引用
|
||||||
|
|
||||||
|
// ========== 响应式数据 ==========
|
||||||
|
const showSearch = ref(true); // 是否显示搜索区域
|
||||||
|
const selectObjs = ref([]) as any; // 表格多选数据
|
||||||
|
const multiple = ref(true); // 是否多选
|
||||||
|
|
||||||
|
// ========== 表格状态 ==========
|
||||||
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
|
queryForm: {}, // 查询参数
|
||||||
|
pageList: fetchList // 分页查询方法
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== Hook引用 ==========
|
||||||
|
// 表格相关Hook
|
||||||
|
const {
|
||||||
|
getDataList,
|
||||||
|
currentChangeHandle,
|
||||||
|
sizeChangeHandle,
|
||||||
|
sortChangeHandle,
|
||||||
|
downBlobFile,
|
||||||
|
tableStyle
|
||||||
|
} = useTable(state);
|
||||||
|
|
||||||
|
// ========== 方法定义 ==========
|
||||||
|
/**
|
||||||
|
* 重置查询条件
|
||||||
|
*/
|
||||||
|
const resetQuery = () => {
|
||||||
|
// 清空搜索条件
|
||||||
|
queryRef.value?.resetFields();
|
||||||
|
// 清空多选
|
||||||
|
selectObjs.value = [];
|
||||||
|
// 重新查询
|
||||||
|
getDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel文件
|
||||||
|
*/
|
||||||
|
const exportExcel = () => {
|
||||||
|
downBlobFile(
|
||||||
|
'/purchase/puchasingAcceptTeam/export',
|
||||||
|
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||||
|
'puchasingAcceptTeam.xlsx'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格多选事件处理
|
||||||
|
* @param objs 选中的数据行
|
||||||
|
*/
|
||||||
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
|
selectObjs.value = objs.map(({ id }) => id);
|
||||||
|
multiple.value = !objs.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据处理
|
||||||
|
* @param ids 要删除的数据ID数组
|
||||||
|
*/
|
||||||
|
const handleDelete = async (ids: string[]) => {
|
||||||
|
try {
|
||||||
|
await useMessageBox().confirm('此操作将永久删除');
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await delObjs(ids);
|
||||||
|
getDataList();
|
||||||
|
useMessage().success('删除成功');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
142
src/views/purchase/purchasingAccept/form.vue
Normal file
142
src/views/purchase/purchasingAccept/form.vue
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||||
|
:close-on-click-modal="false" draggable>
|
||||||
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="remark" prop="remark">
|
||||||
|
<el-input v-model="form.remark" placeholder="请输入remark"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="采购申请ID" prop="purchaseId">
|
||||||
|
<el-input v-model="form.purchaseId" placeholder="请输入采购申请ID"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="验收日期" prop="acceptDate">
|
||||||
|
<el-input v-model="form.acceptDate" placeholder="请输入验收日期"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="验收地点" prop="acceptAddress">
|
||||||
|
<el-input v-model="form.acceptAddress" placeholder="请输入验收地点"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="验收批次" prop="batch">
|
||||||
|
<el-input v-model="form.batch" placeholder="请输入验收批次"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="问题意见" prop="question">
|
||||||
|
<el-input v-model="form.question" placeholder="请输入问题意见"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="PurchasingAcceptDialog">
|
||||||
|
// ========== 1. 导入语句 ==========
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
import { rule } from '/@/utils/validate';
|
||||||
|
import { useMessage } from "/@/hooks/message";
|
||||||
|
import { getObj, addObj, putObj, validateExist } from '/@/api/purchase/purchasingAccept';
|
||||||
|
|
||||||
|
// ========== 2. 组件定义 ==========
|
||||||
|
// 定义组件事件
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
|
// ========== 3. 响应式数据定义 ==========
|
||||||
|
// 基础响应式变量
|
||||||
|
const dataFormRef = ref(); // 表单引用
|
||||||
|
const visible = ref(false); // 弹窗显示状态
|
||||||
|
const loading = ref(false); // 加载状态
|
||||||
|
|
||||||
|
// 表单数据对象
|
||||||
|
const form = reactive({
|
||||||
|
id: '', // 主键
|
||||||
|
remark: '', // ${field.fieldComment}
|
||||||
|
purchaseId: '', // 采购申请ID
|
||||||
|
acceptDate: '', // 验收日期
|
||||||
|
acceptAddress: '', // 验收地点
|
||||||
|
batch: '', // 验收批次
|
||||||
|
question: '', // 问题意见
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 4. 字典数据处理 ==========
|
||||||
|
|
||||||
|
// ========== 5. 表单校验规则 ==========
|
||||||
|
const dataRules = ref({
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 6. 方法定义 ==========
|
||||||
|
// 获取详情数据
|
||||||
|
const getPurchasingAcceptData = async (id: string) => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const { data } = await getObj({ id: id });
|
||||||
|
// 直接将第一条数据赋值给表单
|
||||||
|
Object.assign(form, data[0]);
|
||||||
|
} catch (error) {
|
||||||
|
useMessage().error('获取数据失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹窗方法
|
||||||
|
const openDialog = (id: string) => {
|
||||||
|
visible.value = true;
|
||||||
|
form.id = '';
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
|
nextTick(() => {
|
||||||
|
dataFormRef.value?.resetFields();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取PurchasingAccept信息
|
||||||
|
if (id) {
|
||||||
|
form.id = id;
|
||||||
|
getPurchasingAcceptData(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单方法
|
||||||
|
const onSubmit = async () => {
|
||||||
|
loading.value = true; // 防止重复提交
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||||
|
if (!valid) {
|
||||||
|
loading.value = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 根据是否有ID判断是新增还是修改
|
||||||
|
form.id ? await putObj(form) : await addObj(form);
|
||||||
|
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||||
|
visible.value = false;
|
||||||
|
emit('refresh'); // 通知父组件刷新列表
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== 7. 对外暴露 ==========
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
openDialog
|
||||||
|
});
|
||||||
|
</script>
|
||||||
228
src/views/purchase/purchasingAccept/index.vue
Normal file
228
src/views/purchase/purchasingAccept/index.vue
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-padding">
|
||||||
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
|
|
||||||
|
<!-- 操作按钮区域 -->
|
||||||
|
<el-row>
|
||||||
|
<div class="mb8" style="width: 100%">
|
||||||
|
<el-button
|
||||||
|
icon="folder-add"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="formDialogRef.openDialog()"
|
||||||
|
v-auth="'purchase_purchasingAccept_add'"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
icon="upload-filled"
|
||||||
|
type="primary"
|
||||||
|
class="ml10"
|
||||||
|
@click="excelUploadRef.show()"
|
||||||
|
v-auth="'purchase_purchasingAccept_add'"
|
||||||
|
>
|
||||||
|
导入
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
plain
|
||||||
|
:disabled="multiple"
|
||||||
|
icon="Delete"
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_purchasingAccept_del'"
|
||||||
|
@click="handleDelete(selectObjs)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'purchase_purchasingAccept_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right;"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 数据表格区域 -->
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
|
@selection-change="selectionChangHandle"
|
||||||
|
@sort-change="sortChangeHandle"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
|
<el-table-column type="index" label="#" width="40" />
|
||||||
|
<el-table-column
|
||||||
|
prop="remark"
|
||||||
|
label="remark"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="purchaseId"
|
||||||
|
label="采购申请ID"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="acceptDate"
|
||||||
|
label="验收日期"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="acceptAddress"
|
||||||
|
label="验收地点"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="batch"
|
||||||
|
label="验收批次"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="question"
|
||||||
|
label="问题意见"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_purchasingAccept_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
icon="delete"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'purchase_purchasingAccept_del'"
|
||||||
|
@click="handleDelete([scope.row.id])"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination
|
||||||
|
@size-change="sizeChangeHandle"
|
||||||
|
@current-change="currentChangeHandle"
|
||||||
|
v-bind="state.pagination"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑、新增弹窗 -->
|
||||||
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
|
<!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
|
||||||
|
<upload-excel
|
||||||
|
ref="excelUploadRef"
|
||||||
|
title="导入"
|
||||||
|
url="/purchase/purchasingAccept/import"
|
||||||
|
temp-url="/admin/sys-file/local/file/purchasingAccept.xlsx"
|
||||||
|
@refreshDataList="getDataList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="systemPurchasingAccept">
|
||||||
|
// ========== 导入声明 ==========
|
||||||
|
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||||
|
import { fetchList, delObjs } from "/@/api/purchase/purchasingAccept";
|
||||||
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
|
||||||
|
// ========== 组件声明 ==========
|
||||||
|
// 异步加载表单弹窗组件
|
||||||
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
|
|
||||||
|
// ========== 字典数据 ==========
|
||||||
|
|
||||||
|
// ========== 组件引用 ==========
|
||||||
|
const formDialogRef = ref(); // 表单弹窗引用
|
||||||
|
const excelUploadRef = ref(); // Excel上传弹窗引用
|
||||||
|
const queryRef = ref(); // 查询表单引用
|
||||||
|
|
||||||
|
// ========== 响应式数据 ==========
|
||||||
|
const showSearch = ref(true); // 是否显示搜索区域
|
||||||
|
const selectObjs = ref([]) as any; // 表格多选数据
|
||||||
|
const multiple = ref(true); // 是否多选
|
||||||
|
|
||||||
|
// ========== 表格状态 ==========
|
||||||
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
|
queryForm: {}, // 查询参数
|
||||||
|
pageList: fetchList // 分页查询方法
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== Hook引用 ==========
|
||||||
|
// 表格相关Hook
|
||||||
|
const {
|
||||||
|
getDataList,
|
||||||
|
currentChangeHandle,
|
||||||
|
sizeChangeHandle,
|
||||||
|
sortChangeHandle,
|
||||||
|
downBlobFile,
|
||||||
|
tableStyle
|
||||||
|
} = useTable(state);
|
||||||
|
|
||||||
|
// ========== 方法定义 ==========
|
||||||
|
/**
|
||||||
|
* 重置查询条件
|
||||||
|
*/
|
||||||
|
const resetQuery = () => {
|
||||||
|
// 清空搜索条件
|
||||||
|
queryRef.value?.resetFields();
|
||||||
|
// 清空多选
|
||||||
|
selectObjs.value = [];
|
||||||
|
// 重新查询
|
||||||
|
getDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出Excel文件
|
||||||
|
*/
|
||||||
|
const exportExcel = () => {
|
||||||
|
downBlobFile(
|
||||||
|
'/purchase/purchasingAccept/export',
|
||||||
|
Object.assign(state.queryForm, { ids: selectObjs }),
|
||||||
|
'purchasingAccept.xlsx'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格多选事件处理
|
||||||
|
* @param objs 选中的数据行
|
||||||
|
*/
|
||||||
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
|
selectObjs.value = objs.map(({ id }) => id);
|
||||||
|
multiple.value = !objs.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除数据处理
|
||||||
|
* @param ids 要删除的数据ID数组
|
||||||
|
*/
|
||||||
|
const handleDelete = async (ids: string[]) => {
|
||||||
|
try {
|
||||||
|
await useMessageBox().confirm('此操作将永久删除');
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await delObjs(ids);
|
||||||
|
getDataList();
|
||||||
|
useMessage().success('删除成功');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user