feat: 新增风险图谱算法与系统仪表盘及操作反馈体系
后端新增风险图谱算法模块、风险观察与反馈服务、规则 DSL 校验器和可解释性引擎,完善系统仪表盘和财务仪表盘统计, 优化 agent 运行和编排执行链路,清理旧开发文档,前端新增 系统趋势、负载热力图等多种仪表盘图表组件,完善操作反馈 对话框和工作台日期选择器,优化报销创建和审批详情交互, 补充单元测试覆盖。
This commit is contained in:
@@ -44,6 +44,9 @@ const CHINESE_DAY_NUMBERS = {
|
||||
十: 10
|
||||
}
|
||||
|
||||
const COMPOSER_DATE_RANGE_PREFIX_RE = /^20\d{2}-\d{1,2}-\d{1,2}(?:\s*至\s*20\d{2}-\d{1,2}-\d{1,2})?[,,。\s]*/u
|
||||
const COMPOSER_LABELED_TIME_PREFIX_RE = /^(?:业务)?发生时间[::]\s*[^,,。\n]+(?:至\s*[^,,。\n]+)?[,,。\s]*/u
|
||||
|
||||
function normalizeComposerText(value) {
|
||||
return String(value || '').trim().replace(/\s+/g, ' ')
|
||||
}
|
||||
@@ -85,7 +88,8 @@ function calculateBusinessDays(businessTimeContext) {
|
||||
|
||||
function stripBusinessTimePrefix(text) {
|
||||
return normalizeComposerText(text)
|
||||
.replace(/^(?:业务)?发生时间[::]\s*[^,,。\n]+(?:至\s*[^,,。\n]+)?[,,。\s]*/u, '')
|
||||
.replace(COMPOSER_LABELED_TIME_PREFIX_RE, '')
|
||||
.replace(COMPOSER_DATE_RANGE_PREFIX_RE, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
@@ -183,7 +187,8 @@ export function useTravelReimbursementComposerTools({
|
||||
buildReviewSlotMap,
|
||||
isValidIsoDateString,
|
||||
buildLocallySyncedReviewPayload,
|
||||
formatDateInputValue
|
||||
formatDateInputValue,
|
||||
onComposerDateSelection
|
||||
}) {
|
||||
const composerDatePickerOpen = ref(false)
|
||||
const composerDateMode = ref('single')
|
||||
@@ -217,23 +222,19 @@ export function useTravelReimbursementComposerTools({
|
||||
)
|
||||
function buildComposerBusinessTimeLabel() {
|
||||
if (composerDateMode.value === 'single') {
|
||||
return `发生时间:${composerSingleDate.value}`
|
||||
return composerSingleDate.value
|
||||
}
|
||||
if (composerRangeStartDate.value === composerRangeEndDate.value) {
|
||||
return `发生时间:${composerRangeStartDate.value}`
|
||||
return composerRangeStartDate.value
|
||||
}
|
||||
return `发生时间:${composerRangeStartDate.value} 至 ${composerRangeEndDate.value}`
|
||||
return `${composerRangeStartDate.value} 至 ${composerRangeEndDate.value}`
|
||||
}
|
||||
|
||||
function hasComposerBusinessTimeSelection() {
|
||||
return composerBusinessTimeTags.value.length > 0 || composerBusinessTimeDraftTouched.value
|
||||
}
|
||||
|
||||
function buildComposerBusinessTimeContext() {
|
||||
if (!hasComposerBusinessTimeSelection()) {
|
||||
return null
|
||||
}
|
||||
|
||||
function buildComposerBusinessTimeContextFromSelection() {
|
||||
const mode = composerDateMode.value === 'range' ? 'range' : 'single'
|
||||
const startDate = String(mode === 'range' ? composerRangeStartDate.value : composerSingleDate.value).trim()
|
||||
const endDate = String(mode === 'range' ? composerRangeEndDate.value : startDate).trim()
|
||||
@@ -255,6 +256,28 @@ export function useTravelReimbursementComposerTools({
|
||||
}
|
||||
}
|
||||
|
||||
function buildComposerBusinessTimeContext() {
|
||||
if (!hasComposerBusinessTimeSelection()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return buildComposerBusinessTimeContextFromSelection()
|
||||
}
|
||||
|
||||
function buildComposerBusinessTimeSelection() {
|
||||
const context = buildComposerBusinessTimeContextFromSelection()
|
||||
if (!context) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
label: buildComposerBusinessTimeLabel(),
|
||||
context,
|
||||
mode: context.mode,
|
||||
startDate: context.start_date,
|
||||
endDate: context.end_date
|
||||
}
|
||||
}
|
||||
|
||||
function mergeBusinessTimeIntoExtraContext(extraContext, businessTimeContext) {
|
||||
if (!businessTimeContext) {
|
||||
return extraContext
|
||||
@@ -345,9 +368,60 @@ export function useTravelReimbursementComposerTools({
|
||||
composerDateMode.value = mode === 'range' ? 'range' : 'single'
|
||||
}
|
||||
|
||||
function handleComposerDateInputChange() {
|
||||
composerBusinessTimeDraftTouched.value = true
|
||||
syncComposerBusinessTimeToReviewCard(buildComposerBusinessTimeContext())
|
||||
async function commitComposerDateSelection({ closePicker = true, focusComposer = true } = {}) {
|
||||
if (!composerCanApplyDateSelection.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
const selection = buildComposerBusinessTimeSelection()
|
||||
if (!selection) {
|
||||
return false
|
||||
}
|
||||
|
||||
const handled = onComposerDateSelection?.(selection) === true
|
||||
if (handled) {
|
||||
composerBusinessTimeDraftTouched.value = false
|
||||
composerBusinessTimeTags.value = []
|
||||
} else {
|
||||
composerBusinessTimeDraftTouched.value = true
|
||||
composerBusinessTimeTags.value = [
|
||||
{
|
||||
id: `biz-time-${Date.now()}`,
|
||||
label: selection.label
|
||||
}
|
||||
]
|
||||
syncComposerBusinessTimeToReviewCard(selection.context)
|
||||
}
|
||||
|
||||
if (closePicker) {
|
||||
composerDatePickerOpen.value = false
|
||||
}
|
||||
await nextTick()
|
||||
adjustComposerTextareaHeight()
|
||||
if (focusComposer) {
|
||||
composerTextareaRef.value?.focus()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function handleComposerDateInputChange(part = 'single') {
|
||||
if (composerDateMode.value !== 'range' || part === 'single') {
|
||||
void commitComposerDateSelection()
|
||||
return
|
||||
}
|
||||
|
||||
if (part === 'range-start') {
|
||||
if (!composerRangeEndDate.value || composerRangeEndDate.value < composerRangeStartDate.value) {
|
||||
composerRangeEndDate.value = composerRangeStartDate.value
|
||||
}
|
||||
if (!onComposerDateSelection) {
|
||||
composerBusinessTimeDraftTouched.value = true
|
||||
syncComposerBusinessTimeToReviewCard(buildComposerBusinessTimeContextFromSelection())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
void commitComposerDateSelection()
|
||||
}
|
||||
|
||||
function removeComposerBusinessTimeTag(tagId) {
|
||||
@@ -376,22 +450,7 @@ export function useTravelReimbursementComposerTools({
|
||||
}
|
||||
|
||||
async function applyComposerDateSelection() {
|
||||
if (!composerCanApplyDateSelection.value) {
|
||||
return
|
||||
}
|
||||
|
||||
composerBusinessTimeDraftTouched.value = true
|
||||
composerBusinessTimeTags.value = [
|
||||
{
|
||||
id: `biz-time-${Date.now()}`,
|
||||
label: buildComposerBusinessTimeLabel()
|
||||
}
|
||||
]
|
||||
syncComposerBusinessTimeToReviewCard(buildComposerBusinessTimeContext())
|
||||
composerDatePickerOpen.value = false
|
||||
await nextTick()
|
||||
adjustComposerTextareaHeight()
|
||||
composerTextareaRef.value?.focus()
|
||||
await commitComposerDateSelection()
|
||||
}
|
||||
|
||||
function resolveTravelCalculatorInitialDays() {
|
||||
@@ -547,6 +606,7 @@ export function useTravelReimbursementComposerTools({
|
||||
travelCalculatorCanSubmit,
|
||||
buildComposerBusinessTimeLabel,
|
||||
hasComposerBusinessTimeSelection,
|
||||
buildComposerBusinessTimeSelection,
|
||||
buildComposerBusinessTimeContext,
|
||||
mergeBusinessTimeIntoExtraContext,
|
||||
syncComposerBusinessTimeToReviewCard,
|
||||
|
||||
Reference in New Issue
Block a user