diff --git a/frontend/src/api/businessRoles.ts b/frontend/src/api/businessRoles.ts new file mode 100644 index 0000000..eaadf70 --- /dev/null +++ b/frontend/src/api/businessRoles.ts @@ -0,0 +1,90 @@ +import { request } from './request' +import type { PageData } from './types' + +/** 公式模板下拉项(含声明参数,供岗位表单展示) */ +export interface TemplateOption { + code: string + name: string + description: string + params: { code: string; name: string }[] +} + +/** 岗位角色列表项(对应后端 `BusinessRoleOut`) */ +export interface BusinessRoleItem { + id: number + role_code: string + role_name: string + calc_template: string + description: string | null + sort_order: number + status: number + /** 1内置(禁删禁停) 0自定义 */ + is_builtin: number +} + +export interface BusinessRoleQueryParams { + pageNum?: number + pageSize?: number + keyword?: string + status?: number +} + +export interface BusinessRoleCreateParams { + role_code: string + role_name: string + calc_template: string + description?: string + sort_order?: number +} + +/** 编辑:不含 role_code(创建后不可修改,编码是参数维度与模板绑定的锚点) */ +export interface BusinessRoleUpdateParams { + role_name: string + calc_template: string + description?: string + sort_order?: number +} + +/** 分页查询岗位角色(含停用) */ +export function listBusinessRoles( + params: BusinessRoleQueryParams, +): Promise> { + return request({ url: '/v1/system/business-roles', method: 'get', params }) +} + +/** 新增岗位 */ +export function createBusinessRole( + data: BusinessRoleCreateParams, +): Promise { + return request({ url: '/v1/system/business-roles', method: 'post', data }) +} + +/** 编辑岗位 */ +export function updateBusinessRole( + roleId: number, + data: BusinessRoleUpdateParams, +): Promise { + return request({ url: `/v1/system/business-roles/${roleId}`, method: 'put', data }) +} + +/** 删除岗位(内置岗位后端拒绝,前端同步禁用按钮) */ +export function deleteBusinessRole(roleId: number): Promise { + return request({ url: `/v1/system/business-roles/${roleId}`, method: 'delete' }) +} + +/** 启用 / 禁用(内置岗位后端拒绝停用) */ +export function setBusinessRoleStatus( + roleId: number, + status: number, +): Promise { + return request({ + url: `/v1/system/business-roles/${roleId}/status`, + method: 'put', + data: { status }, + }) +} + +/** 公式模板下拉(含声明参数说明) */ +export function listTemplateOptions(): Promise { + return request({ url: '/v1/system/business-roles/meta/templates', method: 'get' }) +} diff --git a/frontend/src/api/params.ts b/frontend/src/api/params.ts new file mode 100644 index 0000000..d8a50b0 --- /dev/null +++ b/frontend/src/api/params.ts @@ -0,0 +1,208 @@ +import service, { request } from './request' +import type { PageData } from './types' + +/** 参数目录项(含各维度截至查询时点的生效值) */ +export interface ParamDimensionValue { + dimension_value: string + value_text: string + effective_date: string | null +} + +export interface ParamCatalogItem { + param_code: string + param_name: string + param_group: string + value_type: string + unit: string | null + dimension_type: string + options: string[] + default_value: string | null + value_min: string | null + value_max: string | null + description: string | null + values: ParamDimensionValue[] +} + +/** 参数目录(asOf 缺省为今日) */ +export function getCatalog(asOf?: string): Promise { + return request({ url: '/v1/system/params', method: 'get', params: asOf ? { as_of: asOf } : {} }) +} + +/** 变更条目:参数 + 维度 + 新值 */ +export interface ParamChangeItem { + param_code: string + dimension_value: string + value: string +} + +export interface ParamChangePayload { + /** 生效方式:1立即生效 2指定日期生效 */ + change_type: number + effective_date?: string + remark?: string + items: ParamChangeItem[] +} + +export interface ParamChangeBatch { + id: number + version_no: string + effective_date: string + change_type: number + remark: string | null + operator_name: string + item_count: number + create_time: string +} + +/** 提交变更批次 */ +export function submitChanges(data: ParamChangePayload): Promise { + return request({ url: '/v1/system/params/changes', method: 'post', data }) +} + +export interface ParamBatchItem { + param_code: string + param_name: string + dimension_value: string + old_value_text: string | null + value_text: string + effective_date: string +} + +export interface ParamBatchDetail { + id: number + version_no: string + effective_date: string + change_type: number + remark: string | null + operator_name: string + item_count: number + create_time: string + items: ParamBatchItem[] +} + +/** 批次明细(旧值 → 新值) */ +export function getBatchDetail(batchId: number): Promise { + return request({ url: `/v1/system/params/changes/${batchId}`, method: 'get' }) +} + +export interface ParamBatch { + id: number + version_no: string + effective_date: string + change_type: number + remark: string | null + operator_name: string + item_count: number + create_time: string +} + +/** 变更记录分页 */ +export function listBatches(params: { + pageNum?: number + pageSize?: number + start_date?: string + end_date?: string +}): Promise> { + return request({ url: '/v1/system/params/changes', method: 'get', params }) +} + +/** 撤回未生效批次 */ +export function withdrawBatch(batchId: number): Promise { + return request({ url: `/v1/system/params/changes/${batchId}`, method: 'delete' }) +} + +export interface ParamDiff { + param_code: string + param_name: string + param_group: string + dimension_value: string + old_value: string | null + new_value: string | null + changed: boolean +} + +/** 两日期快照对比 */ +export function compareParams(fromDate: string, toDate: string): Promise { + return request({ + url: '/v1/system/params/compare', + method: 'get', + params: { from_date: fromDate, to_date: toDate }, + }) +} + +export interface ParamHistory { + version_no: string + dimension_value: string + old_value_text: string | null + value_text: string + effective_date: string + operator_name: string + create_time: string +} + +/** 单参数版本历史 */ +export function getParamHistory( + paramCode: string, + params: { pageNum?: number; pageSize?: number; dimension_value?: string }, +): Promise> { + return request({ url: `/v1/system/params/${paramCode}/history`, method: 'get', params }) +} + +/** + * 导出变更记录(文件流)。 + * + * 走 axios 实例(带令牌)而非 request 封装:响应是 xlsx 文件流, + * 不是统一信封,拦截器已对 responseType=blob 直通。 + */ +export async function exportChanges(params: { + start_date?: string + end_date?: string +}): Promise { + const response = await service.get('/v1/system/params/export', { + params, + responseType: 'blob', + }) + return response.data as Blob +} + +/** 计算预览入参(金额为字符串,Decimal 承载) */ +export interface ParamPreviewPayload { + business_role?: string + customer_type?: string + product_category?: string + ship_date: string + receipt_date: string + revenue: string + profit: string + received_amount: string + barter: boolean + probation: boolean +} + +export interface ParamUsed { + param_code: string + value_text: string + effective_date: string | null +} + +export interface ParamPreviewResult { + payment_days: number + rate: string + rate_text: string + profit_rate: string + converted_profit: string + performance_amount: string + barter_applied: boolean + performance_after_barter: string | null + start_payment_ok: boolean + payment_weight_r: number + payment_weight: string + payable_amount: string + probation_note: string | null + params_used: ParamUsed[] +} + +/** 计算预览 */ +export function previewCalc(data: ParamPreviewPayload): Promise { + return request({ url: '/v1/system/params/preview', method: 'post', data }) +} diff --git a/frontend/src/api/request.ts b/frontend/src/api/request.ts index 7f6ff39..b4fb33e 100644 --- a/frontend/src/api/request.ts +++ b/frontend/src/api/request.ts @@ -51,6 +51,10 @@ function handleUnauthorized(message: string): void { service.interceptors.response.use( (response: AxiosResponse) => { + // 文件流(导出下载)不是统一信封,直通给调用方处理 + if (response.config.responseType === 'blob') { + return response + } const body = response.data if (body.code !== 200) { // 防御性分支:后端非 2xx 走 reject 拦截器,这里是 2xx 但业务码异常的情况 diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 51c84ef..08e4639 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -52,11 +52,23 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/views/system/roles/index.vue'), meta: { title: '角色管理', group: '系统管理', requiresAdmin: true, order: 3 }, }, + { + path: '/system/business-roles', + name: 'system-business-roles', + component: () => import('@/views/system/business-roles/index.vue'), + meta: { title: '岗位角色', group: '系统管理', requiresAdmin: true, order: 5 }, + }, + { + path: '/system/params', + name: 'system-params', + component: () => import('@/views/system/params/index.vue'), + meta: { title: '计提参数', group: '系统管理', requiresAdmin: true, order: 6 }, + }, { path: '/system/logs', name: 'system-logs', component: () => import('@/views/system/logs/index.vue'), - meta: { title: '日志查询', group: '系统管理', requiresAdmin: true, order: 4 }, + meta: { title: '日志查询', group: '系统管理', requiresAdmin: true, order: 7 }, }, ], }, diff --git a/frontend/src/utils/constants.ts b/frontend/src/utils/constants.ts index 8109b6d..37ec5e0 100644 --- a/frontend/src/utils/constants.ts +++ b/frontend/src/utils/constants.ts @@ -7,7 +7,7 @@ export const ROLE_ADMIN = 'admin' * 操作日志的模块 / 操作词表 —— 与后端 `core/constants.py` 的 * `MODULE_*` / `ACTION_*` 保持一致;新增模块时两处同步(后端是权威来源)。 */ -export const MODULE_OPTIONS = ['用户管理', '角色管理'] as const +export const MODULE_OPTIONS = ['用户管理', '角色管理', '岗位角色', '计提参数'] as const export const ACTION_OPTIONS = ['新增', '修改', '删除', '重置密码', '启用', '禁用'] as const /** 启用/禁用筛选选项(文案与 StatusTag 的展示一致) */ diff --git a/frontend/src/views/system/business-roles/index.vue b/frontend/src/views/system/business-roles/index.vue new file mode 100644 index 0000000..f0b3a74 --- /dev/null +++ b/frontend/src/views/system/business-roles/index.vue @@ -0,0 +1,374 @@ + + + + + diff --git a/frontend/src/views/system/params/index.vue b/frontend/src/views/system/params/index.vue new file mode 100644 index 0000000..aae4091 --- /dev/null +++ b/frontend/src/views/system/params/index.vue @@ -0,0 +1,973 @@ + + + + +