fix(加班申请): 使用后端专门返回状态的接口,代替使用字典。

fix(status-tag.ts):把产品需求、项目需求的状态颜色定义收敛到此处。
This commit is contained in:
dk
2026-06-04 10:49:34 +08:00
parent 9d84b1aae0
commit acef4418d8
9 changed files with 77 additions and 56 deletions

View File

@@ -112,14 +112,6 @@ export const RDMS_REQ_CAN_DELETE_STATUS_DICT_CODE = 'rdms_req_can_delete_status'
*/ */
export const RDMS_WORKLOG_DIFFICULTY_DICT_CODE = 'rdms_task_item_worklog_difficulty'; export const RDMS_WORKLOG_DIFFICULTY_DICT_CODE = 'rdms_task_item_worklog_difficulty';
/**
* 加班申请状态字典编码
*
* 对应业务字段:加班申请中的 statusCode
* 来源口径:`overtime-application-design.md` 明确状态字典为 rdms_overtime_application_status
*/
export const RDMS_OVERTIME_APPLICATION_STATUS_DICT_CODE = 'rdms_overtime_application_status';
/** /**
* 加班时长快捷选项字典编码 * 加班时长快捷选项字典编码
* *

View File

@@ -14,7 +14,8 @@ export type StatusDomain =
| 'taskAssigneeMember' | 'taskAssigneeMember'
| 'project' | 'project'
| 'product' | 'product'
| 'requirement' | 'productRequirement'
| 'projectRequirement'
| 'workOrder' | 'workOrder'
| 'personalItem' | 'personalItem'
| 'overtimeApplication'; | 'overtimeApplication';
@@ -52,8 +53,31 @@ const statusTagTypeRegistry: Record<StatusDomain, Record<string, StatusTagType>>
project: {}, project: {},
// 产品(待补全) // 产品(待补全)
product: {}, product: {},
// 需求(待补全) // 产品需求
requirement: {}, productRequirement: {
pending_claim: 'info',
pending_review: 'info',
pending_dispatch: 'primary',
reviewed: 'success',
review_rejected: 'danger',
implementing: 'primary',
accepted: 'success',
closed: 'danger',
rejected: 'danger',
cancelled: 'danger'
},
// 项目需求
projectRequirement: {
pending_claim: 'info',
pending_review: 'info',
reviewed: 'success',
review_rejected: 'danger',
implementing: 'primary',
accepted: 'success',
closed: 'danger',
rejected: 'danger',
cancelled: 'danger'
},
// 工单(待补全) // 工单(待补全)
workOrder: {}, workOrder: {},
// 个人事项 // 个人事项
@@ -83,7 +107,3 @@ export function getStatusTagType(domain: StatusDomain, statusCode: string | null
export function getPersonalItemStatusTagType(statusCode: string | null | undefined) { export function getPersonalItemStatusTagType(statusCode: string | null | undefined) {
return getStatusTagType('personalItem', statusCode); return getStatusTagType('personalItem', statusCode);
} }
export function getOvertimeApplicationStatusTagType(statusCode: string | null | undefined) {
return getStatusTagType('overtimeApplication', statusCode);
}

View File

@@ -269,6 +269,19 @@ export async function fetchGetOvertimeApplicationStatusLogs(id: string) {
); );
} }
export async function fetchGetOvertimeApplicationStatusDict() {
const result = await request<Api.OvertimeApplication.OvertimeApplicationStatusDict[]>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/status/dict`,
method: 'get'
});
return mapServiceResult(
result as ServiceRequestResult<Api.OvertimeApplication.OvertimeApplicationStatusDict[]>,
data => data
);
}
export function fetchExportOvertimeApplications(params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}) { export function fetchExportOvertimeApplications(params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}) {
const query = createPageQuery(params); const query = createPageQuery(params);

View File

@@ -74,5 +74,14 @@ declare namespace Api {
remark?: string | null; remark?: string | null;
createTime: string; createTime: string;
} }
interface OvertimeApplicationStatusDict {
statusCode: string;
statusName: string;
sort: number;
initialFlag: boolean;
terminalFlag: boolean;
allowEdit: boolean;
}
} }
} }

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, watch } from 'vue'; import { computed, onMounted, reactive, ref, watch } from 'vue';
import { RDMS_OVERTIME_APPLICATION_STATUS_DICT_CODE } from '@/constants/dict'; import { fetchGetOvertimeApplicationStatusDict } from '@/service/api';
import TableSearchFields, { type SearchField } from '@/components/custom/table-search-fields.vue'; import TableSearchFields, { type SearchField } from '@/components/custom/table-search-fields.vue';
defineOptions({ name: 'OvertimeApplicationSearch' }); defineOptions({ name: 'OvertimeApplicationSearch' });
@@ -21,6 +21,8 @@ const searchModel = reactive<Record<string, any>>({
approverName: '' approverName: ''
}); });
const statusOptions = ref<Array<{ label: string; value: string }>>([]);
let syncingFromSource = false; let syncingFromSource = false;
watch( watch(
@@ -53,6 +55,24 @@ watch(
{ flush: 'sync' } { flush: 'sync' }
); );
async function loadStatusOptions() {
const { error, data } = await fetchGetOvertimeApplicationStatusDict();
if (error || !data) {
statusOptions.value = [];
return;
}
statusOptions.value = data.map(item => ({
label: item.statusName,
value: item.statusCode
}));
}
onMounted(async () => {
await loadStatusOptions();
});
const fields = computed<SearchField[]>(() => [ const fields = computed<SearchField[]>(() => [
{ {
key: 'applicantName', key: 'applicantName',
@@ -69,8 +89,8 @@ const fields = computed<SearchField[]>(() => [
{ {
key: 'statusCode', key: 'statusCode',
label: '状态', label: '状态',
type: 'dict', type: 'select',
dictCode: RDMS_OVERTIME_APPLICATION_STATUS_DICT_CODE, options: statusOptions.value,
placeholder: '请选择状态' placeholder: '请选择状态'
}, },
{ {

View File

@@ -10,6 +10,7 @@ import {
RDMS_REQ_PRIORITY_DICT_CODE, RDMS_REQ_PRIORITY_DICT_CODE,
RDMS_REQ_SOURCE_TYPE_DICT_CODE RDMS_REQ_SOURCE_TYPE_DICT_CODE
} from '@/constants/dict'; } from '@/constants/dict';
import { getStatusTagType } from '@/constants/status-tag';
import { import {
fetchChangeRequirementStatus, fetchChangeRequirementStatus,
fetchDeleteRequirement, fetchDeleteRequirement,
@@ -31,7 +32,6 @@ import {
ACTION_TYPE_MAP, ACTION_TYPE_MAP,
type RequirementStatusActionCode, type RequirementStatusActionCode,
getRequirementActionDisplayName, getRequirementActionDisplayName,
getRequirementStatusTagType,
isRequirementActionNeedProject, isRequirementActionNeedProject,
isRequirementActionNeedReviewChoice, isRequirementActionNeedReviewChoice,
isRequirementActionTerminal isRequirementActionTerminal
@@ -375,7 +375,7 @@ const columns = computed(() => [
width: 100, width: 100,
align: 'center', align: 'center',
formatter: (row: Api.Product.Requirement) => ( formatter: (row: Api.Product.Requirement) => (
<ElTag type={getRequirementStatusTagType(row.statusCode)}>{getStatusLabel(row.statusCode)}</ElTag> <ElTag type={getStatusTagType('productRequirement', row.statusCode)}>{getStatusLabel(row.statusCode)}</ElTag>
) )
}, },
{ {

View File

@@ -90,22 +90,7 @@ export const ACTION_TYPE_MAP: Record<string, 'primary' | 'success' | 'danger'> =
close: 'danger', close: 'danger',
delete: 'danger' delete: 'danger'
}; };
export function getRequirementStatusTagType(status: Api.Product.RequirementStatusCode): UI.ThemeColor {
const statusTagTypeMap: Record<Api.Product.RequirementStatusCode, UI.ThemeColor> = {
pending_claim: 'info',
pending_review: 'info',
pending_dispatch: 'primary',
reviewed: 'success',
review_rejected: 'danger',
implementing: 'primary',
accepted: 'success',
closed: 'danger',
rejected: 'danger',
cancelled: 'danger'
};
return statusTagTypeMap[status];
}
export function isRequirementActionTerminal(actionCode: RequirementStatusActionCode) { export function isRequirementActionTerminal(actionCode: RequirementStatusActionCode) {
const terminalActions: RequirementStatusActionCode[] = ['reject', 'cancel', 'close']; const terminalActions: RequirementStatusActionCode[] = ['reject', 'cancel', 'close'];
return terminalActions.includes(actionCode); return terminalActions.includes(actionCode);

View File

@@ -9,6 +9,7 @@ import {
RDMS_REQ_PRIORITY_DICT_CODE, RDMS_REQ_PRIORITY_DICT_CODE,
RDMS_REQ_SOURCE_TYPE_DICT_CODE RDMS_REQ_SOURCE_TYPE_DICT_CODE
} from '@/constants/dict'; } from '@/constants/dict';
import { getStatusTagType } from '@/constants/status-tag';
import { import {
fetchChangeProjectRequirementStatus, fetchChangeProjectRequirementStatus,
fetchDeleteProjectRequirement, fetchDeleteProjectRequirement,
@@ -28,7 +29,6 @@ import {
getProjectRequirementActionButtonType, getProjectRequirementActionButtonType,
getProjectRequirementActionDisplayName, getProjectRequirementActionDisplayName,
getProjectRequirementActionIcon, getProjectRequirementActionIcon,
getProjectRequirementStatusTagType,
isProjectRequirementActionTerminal isProjectRequirementActionTerminal
} from './shared/requirement-master-data'; } from './shared/requirement-master-data';
import RequirementActionDialog from './modules/requirement-action-dialog.vue'; import RequirementActionDialog from './modules/requirement-action-dialog.vue';
@@ -377,7 +377,7 @@ const columns = computed(() => [
width: 110, width: 110,
align: 'center', align: 'center',
formatter: (row: Api.Project.ProjectRequirement) => ( formatter: (row: Api.Project.ProjectRequirement) => (
<ElTag type={getProjectRequirementStatusTagType(row.statusCode)}>{getStatusLabel(row.statusCode)}</ElTag> <ElTag type={getStatusTagType('projectRequirement', row.statusCode)}>{getStatusLabel(row.statusCode)}</ElTag>
) )
}, },
{ {

View File

@@ -77,24 +77,6 @@ function resolveActionKeyword(actionCode: string) {
return Object.keys(ACTION_ICON_MAP).find(keyword => actionCode.includes(keyword)); return Object.keys(ACTION_ICON_MAP).find(keyword => actionCode.includes(keyword));
} }
/**
* 获取项目需求状态的标签颜色
*/
export function getProjectRequirementStatusTagType(status: Api.Project.ProjectRequirementStatusCode): UI.ThemeColor {
const statusTagTypeMap: Record<Api.Project.ProjectRequirementStatusCode, UI.ThemeColor> = {
pending_claim: 'info',
pending_review: 'info',
reviewed: 'success',
review_rejected: 'danger',
implementing: 'primary',
accepted: 'success',
closed: 'danger',
rejected: 'danger',
cancelled: 'danger'
};
return statusTagTypeMap[status];
}
/** /**
* 判断动作是否为终态动作 * 判断动作是否为终态动作
* *