style: 全局 UI 主题皮肤重构与样式模块化
引入 Element Plus 主题定制和主题皮肤 composable,将全局 样式拆分为组件级独立 CSS 文件(侧边栏、顶栏、工作台等), 统一色彩变量和间距规范,重构所有视图和组件样式以适配新 主题系统,优化图表和知识图谱组件视觉表现,提取审计和差 旅报销相关子组件。
This commit is contained in:
@@ -29,35 +29,35 @@
|
||||
<input v-model="listKeyword" type="search" placeholder="搜索单号、申请人、部门、归档类型..." />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="dropdown in filterDropdowns"
|
||||
:key="dropdown.key"
|
||||
class="archive-dropdown-filter"
|
||||
:class="{ open: openFilterKey === dropdown.key }"
|
||||
<el-dropdown
|
||||
v-for="menu in filterMenus"
|
||||
:key="menu.key"
|
||||
class="archive-filter-control"
|
||||
trigger="click"
|
||||
placement="bottom-start"
|
||||
popper-class="archive-filter-menu"
|
||||
@command="selectFilterValue(menu.key, $event)"
|
||||
>
|
||||
<button class="filter-btn" type="button" @click="toggleFilterDropdown(dropdown.key)">
|
||||
<span>{{ dropdown.label }}</span>
|
||||
<button class="filter-btn archive-filter-trigger" type="button">
|
||||
<span>{{ menu.label }}</span>
|
||||
<i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div
|
||||
v-if="openFilterKey === dropdown.key"
|
||||
class="archive-dropdown-menu"
|
||||
role="menu"
|
||||
:aria-label="`${dropdown.label}筛选`"
|
||||
>
|
||||
<button
|
||||
v-for="option in dropdown.options"
|
||||
:key="`${dropdown.key}-${option.value}`"
|
||||
type="button"
|
||||
class="archive-dropdown-option"
|
||||
:class="{ active: dropdown.activeValue === option.value }"
|
||||
role="menuitem"
|
||||
@click="selectFilterValue(dropdown.key, option.value)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="option in menu.options"
|
||||
:key="`${menu.key}-${option.value}`"
|
||||
:command="option.value"
|
||||
:class="{ 'is-active': menu.activeValue === option.value }"
|
||||
class="archive-filter-option"
|
||||
:aria-current="menu.activeValue === option.value ? 'true' : undefined"
|
||||
>
|
||||
<i v-if="menu.activeValue === option.value" class="mdi mdi-check"></i>
|
||||
<span>{{ option.label }}</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,27 +35,19 @@
|
||||
<div class="budget-filter-set">
|
||||
<label>
|
||||
<span>预算年度</span>
|
||||
<select v-model="filters.year">
|
||||
<option v-for="year in years" :key="year" :value="year">{{ year }}年度</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="filters.year" :options="yearOptions" />
|
||||
</label>
|
||||
<label>
|
||||
<span>预算季度</span>
|
||||
<select v-model="filters.quarter">
|
||||
<option v-for="quarter in quarters" :key="quarter" :value="quarter">{{ quarter }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="filters.quarter" :options="quarters" />
|
||||
</label>
|
||||
<label>
|
||||
<span>费用类型</span>
|
||||
<select v-model="filters.expenseType">
|
||||
<option v-for="type in expenseTypes" :key="type">{{ type }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="filters.expenseType" :options="expenseTypes" />
|
||||
</label>
|
||||
<label>
|
||||
<span>状态</span>
|
||||
<select v-model="filters.status">
|
||||
<option v-for="status in statuses" :key="status">{{ status }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="filters.status" :options="statuses" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="budget-action-set">
|
||||
@@ -158,14 +150,13 @@
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<label class="budget-page-size">
|
||||
<select v-model.number="budgetPageSize" aria-label="每页条数">
|
||||
<option v-for="size in budgetPageSizeOptions" :key="size" :value="size">
|
||||
{{ size }} 条/页
|
||||
</option>
|
||||
</select>
|
||||
<i class="mdi mdi-chevron-down"></i>
|
||||
</label>
|
||||
<EnterpriseSelect
|
||||
v-model="budgetPageSize"
|
||||
class="budget-page-size-select"
|
||||
:options="budgetPageSizeOptions"
|
||||
aria-label="每页条数"
|
||||
size="small"
|
||||
/>
|
||||
<span class="budget-page-summary">
|
||||
共 {{ totalBudgetRows }} 条,当前第 {{ budgetPage }} / {{ totalBudgetPages }} 页
|
||||
</span>
|
||||
@@ -232,23 +223,15 @@
|
||||
<div class="budget-edit-form-grid">
|
||||
<label class="required">
|
||||
<span>预算年度</span>
|
||||
<select v-model="budgetEditForm.budgetYear">
|
||||
<option v-for="year in years" :key="year" :value="year">{{ year }}年度</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="budgetEditForm.budgetYear" :options="yearOptions" />
|
||||
</label>
|
||||
<label class="required">
|
||||
<span>预算季度</span>
|
||||
<select v-model="budgetEditForm.budgetQuarter">
|
||||
<option v-for="quarter in quarters" :key="quarter" :value="quarter">{{ quarter }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="budgetEditForm.budgetQuarter" :options="quarters" />
|
||||
</label>
|
||||
<label v-if="canSwitchDepartments" class="required">
|
||||
<span>所属部门</span>
|
||||
<select v-model="budgetEditForm.departmentCode">
|
||||
<option v-for="department in departments" :key="department.code" :value="department.code">
|
||||
{{ department.name }}
|
||||
</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="budgetEditForm.departmentCode" :options="departmentOptions" />
|
||||
</label>
|
||||
<label v-else class="required">
|
||||
<span>所属部门</span>
|
||||
@@ -279,26 +262,19 @@
|
||||
<tbody>
|
||||
<tr v-for="row in budgetEditRows" :key="row.id">
|
||||
<td>
|
||||
<select v-model="row.budgetSubjectCode" @change="syncBudgetRowSubject(row)">
|
||||
<option
|
||||
v-for="option in expenseTypeOptions"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="row.budgetSubjectCode"
|
||||
:options="expenseTypeOptions"
|
||||
size="small"
|
||||
@change="syncBudgetRowSubject(row)"
|
||||
/>
|
||||
</td>
|
||||
<td><input v-model="row.budgetAmount" type="text" inputmode="decimal" /></td>
|
||||
<td>
|
||||
<select v-model="row.warningThreshold">
|
||||
<option v-for="warning in warningOptions" :key="warning">{{ warning }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="row.warningThreshold" :options="warningOptions" size="small" />
|
||||
</td>
|
||||
<td>
|
||||
<select v-model="row.controlAction">
|
||||
<option v-for="action in controlActionOptions" :key="action">{{ action }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="row.controlAction" :options="controlActionOptions" size="small" />
|
||||
</td>
|
||||
<td><input v-model="row.budgetRemark" type="text" /></td>
|
||||
<td>
|
||||
|
||||
@@ -232,24 +232,7 @@
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="page-size-wrap">
|
||||
<button class="page-size" type="button" @click="pageSizeOpen = !pageSizeOpen">
|
||||
{{ pageSize }} 条/页 <i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
|
||||
<button
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
type="button"
|
||||
role="option"
|
||||
:aria-selected="pageSize === size"
|
||||
:class="{ active: pageSize === size }"
|
||||
@click="changePageSize(size)"
|
||||
>
|
||||
{{ size }} 条/页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<EnterpriseSelect v-model="pageSize" class="page-size-select" :options="pageSizeOptions" size="small" @change="changePageSize" />
|
||||
</footer>
|
||||
</article>
|
||||
</section>
|
||||
@@ -258,6 +241,7 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import EnterpriseSelect from '../components/shared/EnterpriseSelect.vue'
|
||||
import TableEmptyState from '../components/shared/TableEmptyState.vue'
|
||||
import TableLoadingState from '../components/shared/TableLoadingState.vue'
|
||||
import { mapExpenseClaimToRequest } from '../composables/useRequests.js'
|
||||
@@ -321,7 +305,7 @@ const FILTER_CONFIG_BY_SCOPE = {
|
||||
showDocumentType: false
|
||||
}
|
||||
}
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOptions = [10, 20, 50].map((size) => ({ label: `${size} 条/页`, value: size }))
|
||||
const documentTypeOptions = [
|
||||
{ value: DOCUMENT_TYPE_ALL, label: '单据类型' },
|
||||
{ value: DOCUMENT_TYPE_APPLICATION, label: '申请单' },
|
||||
@@ -356,7 +340,6 @@ const appliedStart = ref('')
|
||||
const appliedEnd = ref('')
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(20)
|
||||
const pageSizeOpen = ref(false)
|
||||
const archiveRows = ref([])
|
||||
const approvalRows = ref([])
|
||||
const supportingLoading = ref(false)
|
||||
@@ -519,7 +502,7 @@ const emptyState = computed(() => {
|
||||
icon: 'mdi mdi-file-sign-outline',
|
||||
actionLabel: '',
|
||||
actionIcon: '',
|
||||
tone: 'emerald',
|
||||
tone: 'theme',
|
||||
artLabel: 'APPLY',
|
||||
tips: ['申请、报销、审批与归档统一在此查看', '申请批准后可继续发起报销']
|
||||
}
|
||||
@@ -534,7 +517,7 @@ const emptyState = computed(() => {
|
||||
icon: filtered ? 'mdi mdi-magnify-scan' : 'mdi mdi-file-document-multiple-outline',
|
||||
actionLabel: '',
|
||||
actionIcon: '',
|
||||
tone: 'emerald',
|
||||
tone: 'theme',
|
||||
artLabel: filtered ? 'FILTER' : 'DOCS',
|
||||
tips: ['单据中心已接入当前报销单据', '归档视角会同步已归档数据']
|
||||
}
|
||||
@@ -724,7 +707,6 @@ function handleEmptyAction() {
|
||||
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
@@ -782,14 +764,12 @@ watch(
|
||||
[activeScopeTab, activeStatusTab, activeDocumentType, activeScene, listKeyword, appliedStart, appliedEnd],
|
||||
() => {
|
||||
currentPage.value = 1
|
||||
pageSizeOpen.value = false
|
||||
}
|
||||
)
|
||||
|
||||
watch(activeFilterConfig, () => {
|
||||
openFilterKey.value = ''
|
||||
datePopover.value = false
|
||||
pageSizeOpen.value = false
|
||||
|
||||
if (!showDocumentTypeFilter.value) {
|
||||
activeDocumentType.value = DOCUMENT_TYPE_ALL
|
||||
|
||||
@@ -665,24 +665,13 @@
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="page-size-wrap">
|
||||
<button class="page-size" type="button" @click="togglePageSizeOpen">
|
||||
{{ pageSize }} 条/页 <i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
|
||||
<button
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
type="button"
|
||||
role="option"
|
||||
:aria-selected="pageSize === size"
|
||||
:class="{ active: pageSize === size }"
|
||||
@click="changePageSize(size)"
|
||||
>
|
||||
{{ size }} 条/页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<EnterpriseSelect
|
||||
v-model="pageSize"
|
||||
class="page-size-select"
|
||||
:options="pageSizeOptions"
|
||||
size="small"
|
||||
@change="changePageSize"
|
||||
/>
|
||||
</footer>
|
||||
</article>
|
||||
</Transition>
|
||||
|
||||
@@ -28,9 +28,12 @@
|
||||
<div class="form-grid">
|
||||
<label class="field">
|
||||
<span><em>*</em> 供应商</span>
|
||||
<select v-model="llmForm.mainProvider" @change="applyProviderPreset('main')">
|
||||
<option v-for="option in providerOptions" :key="option" :value="option">{{ option }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="llmForm.mainProvider"
|
||||
:options="providerOptions"
|
||||
placeholder="选择供应商"
|
||||
@change="applyProviderPreset('main')"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
@@ -101,9 +104,12 @@
|
||||
<div class="form-grid">
|
||||
<label class="field">
|
||||
<span><em>*</em> 供应商</span>
|
||||
<select v-model="llmForm.backupProvider" @change="applyProviderPreset('backup')">
|
||||
<option v-for="option in providerOptions" :key="option" :value="option">{{ option }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="llmForm.backupProvider"
|
||||
:options="providerOptions"
|
||||
placeholder="选择供应商"
|
||||
@change="applyProviderPreset('backup')"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
@@ -174,9 +180,12 @@
|
||||
<div class="form-grid">
|
||||
<label class="field">
|
||||
<span><em>*</em> 供应商</span>
|
||||
<select v-model="llmForm.embeddingProvider" @change="applyProviderPreset('embedding')">
|
||||
<option v-for="option in providerOptions" :key="option" :value="option">{{ option }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="llmForm.embeddingProvider"
|
||||
:options="providerOptions"
|
||||
placeholder="选择供应商"
|
||||
@change="applyProviderPreset('embedding')"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
@@ -251,9 +260,12 @@
|
||||
<div class="form-grid">
|
||||
<label class="field">
|
||||
<span><em>*</em> 供应商</span>
|
||||
<select v-model="llmForm.rerankerProvider" @change="applyProviderPreset('reranker')">
|
||||
<option v-for="option in providerOptions" :key="option" :value="option">{{ option }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="llmForm.rerankerProvider"
|
||||
:options="providerOptions"
|
||||
placeholder="选择供应商"
|
||||
@change="applyProviderPreset('reranker')"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
@@ -306,4 +318,3 @@
|
||||
|
||||
<style scoped src="../assets/styles/views/settings-view-form.css"></style>
|
||||
<style scoped src="../assets/styles/views/settings-view.css"></style>
|
||||
|
||||
|
||||
@@ -27,22 +27,22 @@
|
||||
|
||||
<label class="filter-field">
|
||||
<span>日志级别</span>
|
||||
<select v-model="systemLevelFilter">
|
||||
<option value="">全部</option>
|
||||
<option v-for="level in systemLevelOptions" :key="level" :value="level">
|
||||
{{ level }}
|
||||
</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="systemLevelFilter"
|
||||
:options="systemLevelFilterOptions"
|
||||
placeholder="全部"
|
||||
size="small"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="filter-field">
|
||||
<span>事件类型</span>
|
||||
<select v-model="systemEventTypeFilter">
|
||||
<option value="">全部</option>
|
||||
<option v-for="eventType in systemEventTypeOptions" :key="eventType" :value="eventType">
|
||||
{{ eventType }}
|
||||
</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="systemEventTypeFilter"
|
||||
:options="systemEventTypeFilterOptions"
|
||||
placeholder="全部"
|
||||
size="small"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<button
|
||||
@@ -221,24 +221,13 @@
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="page-size-wrap">
|
||||
<button class="page-size" type="button" @click="pageSizeOpen = !pageSizeOpen">
|
||||
{{ pageSize }} 条/页 <i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
|
||||
<button
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
type="button"
|
||||
role="option"
|
||||
:aria-selected="pageSize === size"
|
||||
:class="{ active: pageSize === size }"
|
||||
@click="changePageSize(size)"
|
||||
>
|
||||
{{ size }} 条/页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<EnterpriseSelect
|
||||
v-model="pageSize"
|
||||
class="page-size-select"
|
||||
:options="pageSizeOptions"
|
||||
size="small"
|
||||
@change="changePageSize"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
|
||||
<label class="field">
|
||||
<span>加密方式</span>
|
||||
<select v-model="mailForm.encryption">
|
||||
<option value="SSL/TLS">SSL/TLS</option>
|
||||
<option value="STARTTLS">STARTTLS</option>
|
||||
<option value="None">无</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="mailForm.encryption"
|
||||
:options="encryptionOptions"
|
||||
placeholder="选择加密方式"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
|
||||
@@ -26,9 +26,13 @@
|
||||
<article class="panel dashboard-card trend-panel">
|
||||
<div class="card-head">
|
||||
<h3>报销申请与审批趋势 <i class="mdi mdi-information-outline"></i></h3>
|
||||
<select v-model="activeTrendRange" class="card-select" aria-label="趋势时间范围">
|
||||
<option v-for="range in trendRanges" :key="range">{{ range }}</option>
|
||||
</select>
|
||||
<EnterpriseSelect
|
||||
v-model="activeTrendRange"
|
||||
class="card-select"
|
||||
:options="trendRanges"
|
||||
aria-label="趋势时间范围"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TrendChart
|
||||
@@ -52,17 +56,21 @@
|
||||
<h3>风险异常分布 <i class="mdi mdi-information-outline"></i></h3>
|
||||
</div>
|
||||
<DonutChart :items="riskLegend" :center-value="`${riskTotal}`" center-label="异常预警单" />
|
||||
<p class="panel-note">* 近30天数据</p>
|
||||
<p class="panel-note">* 近 30 天数据</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="content-grid bottom-grid">
|
||||
<article class="panel dashboard-card rank-panel">
|
||||
<div class="card-head">
|
||||
<h3>部门报销排行(待处理金额) <i class="mdi mdi-information-outline"></i></h3>
|
||||
<select v-model="activeDepartmentRange" class="card-select" aria-label="部门排行时间范围">
|
||||
<option v-for="range in departmentRangeOptions" :key="range">{{ range }}</option>
|
||||
</select>
|
||||
<h3>部门报销排行(待处理金额)<i class="mdi mdi-information-outline"></i></h3>
|
||||
<EnterpriseSelect
|
||||
v-model="activeDepartmentRange"
|
||||
class="card-select"
|
||||
:options="departmentRangeOptions"
|
||||
aria-label="部门排行时间范围"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<BarChart :items="rankedDepartments" />
|
||||
@@ -99,7 +107,7 @@
|
||||
|
||||
<article class="panel dashboard-card budget-panel">
|
||||
<div class="card-head">
|
||||
<h3>预算执行率(本月) <i class="mdi mdi-information-outline"></i></h3>
|
||||
<h3>预算执行率(本月)<i class="mdi mdi-information-outline"></i></h3>
|
||||
</div>
|
||||
|
||||
<GaugeChart
|
||||
@@ -112,7 +120,6 @@
|
||||
<button type="button" class="text-link">查看详情 <i class="mdi mdi-chevron-right"></i></button>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -121,6 +128,7 @@ import TrendChart from '../components/charts/TrendChart.vue'
|
||||
import DonutChart from '../components/charts/DonutChart.vue'
|
||||
import BarChart from '../components/charts/BarChart.vue'
|
||||
import GaugeChart from '../components/charts/GaugeChart.vue'
|
||||
import EnterpriseSelect from '../components/shared/EnterpriseSelect.vue'
|
||||
|
||||
import { useOverviewView } from '../composables/useOverviewView.js'
|
||||
|
||||
@@ -128,8 +136,6 @@ defineProps({
|
||||
filteredRequests: { type: Array, required: true }
|
||||
})
|
||||
|
||||
const emit = defineEmits(['ask'])
|
||||
|
||||
const {
|
||||
activeDepartmentRange,
|
||||
activeTrend,
|
||||
|
||||
@@ -168,24 +168,13 @@
|
||||
<i class="mdi mdi-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="page-size-wrap">
|
||||
<button class="page-size" type="button" @click="pageSizeOpen = !pageSizeOpen">
|
||||
{{ pageSize }} 条/页<i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
|
||||
<button
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
type="button"
|
||||
role="option"
|
||||
:aria-selected="pageSize === size"
|
||||
:class="{ active: pageSize === size }"
|
||||
@click="changePageSize(size)"
|
||||
>
|
||||
{{ size }} 条/页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<EnterpriseSelect
|
||||
v-model="pageSize"
|
||||
class="page-size-select"
|
||||
:options="pageSizeOptions"
|
||||
size="small"
|
||||
@change="changePageSize"
|
||||
/>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -135,14 +135,13 @@
|
||||
<button v-for="p in totalPages" :key="p" class="page-number" :class="{ active: currentPage === p }" type="button" :aria-current="currentPage === p ? 'page' : undefined" @click="currentPage = p">{{ p }}</button>
|
||||
<button class="page-nav" type="button" :disabled="currentPage === totalPages" aria-label="下一页" @click="currentPage++"><i class="mdi mdi-chevron-right"></i></button>
|
||||
</div>
|
||||
<div class="page-size-wrap">
|
||||
<button class="page-size" type="button" @click="pageSizeOpen = !pageSizeOpen">
|
||||
{{ pageSize }} 条/页 <i class="mdi mdi-chevron-down"></i>
|
||||
</button>
|
||||
<div v-if="pageSizeOpen" class="page-size-dropdown" role="listbox">
|
||||
<button v-for="size in pageSizes" :key="size" type="button" role="option" :aria-selected="pageSize === size" :class="{ active: pageSize === size }" @click="changePageSize(size)">{{ size }} 条/页</button>
|
||||
</div>
|
||||
</div>
|
||||
<EnterpriseSelect
|
||||
v-model="pageSize"
|
||||
class="page-size-select"
|
||||
:options="pageSizeOptions"
|
||||
size="small"
|
||||
@change="changePageSize"
|
||||
/>
|
||||
</footer>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
@@ -101,7 +101,54 @@
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template v-else-if="activeSection === 'admin'">
|
||||
<template v-else-if="activeSection === 'appearance'">
|
||||
<section class="settings-card">
|
||||
<div class="card-head">
|
||||
<div class="card-title-with-icon">
|
||||
<div class="model-icon-box slate">
|
||||
<i class="mdi mdi-palette-outline"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4>界面皮肤与企业主色</h4>
|
||||
<p>只调整整体主色、焦点态、按钮和 Element Plus 控件颜色,不改变业务布局。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skin-option-grid">
|
||||
<button
|
||||
v-for="skin in themeSkinOptions"
|
||||
:key="skin.id"
|
||||
class="skin-option"
|
||||
:class="{ active: activeThemeSkinId === skin.id }"
|
||||
type="button"
|
||||
@click="selectThemeSkin(skin.id)"
|
||||
>
|
||||
<span class="skin-swatch" aria-hidden="true">
|
||||
<i :style="{ background: skin.primary }"></i>
|
||||
<i :style="{ background: skin.primarySoftStrong }"></i>
|
||||
<i :style="{ background: skin.secondary }"></i>
|
||||
<i :style="{ background: skin.chartAmber }"></i>
|
||||
</span>
|
||||
<span class="skin-copy">
|
||||
<strong>{{ skin.label }}</strong>
|
||||
<small>{{ skin.desc }}</small>
|
||||
</span>
|
||||
<span v-if="activeThemeSkinId === skin.id" class="skin-current">当前</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="skin-preview-panel">
|
||||
<div>
|
||||
<strong>{{ activeThemeSkin.label }}</strong>
|
||||
<span>当前主色会同步到全局按钮、焦点环、下拉浮层和表单控件。</span>
|
||||
</div>
|
||||
<button class="skin-preview-action" type="button">主按钮</button>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<template v-else-if="activeSection === 'admin'">
|
||||
<section class="settings-card">
|
||||
<div class="card-head">
|
||||
<div class="card-title-with-icon">
|
||||
@@ -365,14 +412,14 @@
|
||||
<input v-model.number="pageState.logForm.retentionDays" type="number" min="7" />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>归档周期</span>
|
||||
<select v-model="pageState.logForm.archiveCycle">
|
||||
<option value="daily">按天归档</option>
|
||||
<option value="weekly">按周归档</option>
|
||||
<option value="monthly">按月归档</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>归档周期</span>
|
||||
<EnterpriseSelect
|
||||
v-model="pageState.logForm.archiveCycle"
|
||||
:options="archiveCycleOptions"
|
||||
placeholder="选择归档周期"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="field field-full">
|
||||
<span><em>*</em> 日志路径</span>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -241,11 +241,7 @@
|
||||
<td class="expense-type col-type">
|
||||
<template v-if="editingExpenseId === item.id">
|
||||
<div class="cell-editor">
|
||||
<select v-model="expenseEditor.itemType" class="editor-select">
|
||||
<option v-for="option in expenseTypeOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
<EnterpriseSelect v-model="expenseEditor.itemType" class="editor-select" :options="expenseTypeOptions" size="small" />
|
||||
<span>编辑费用项目</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -763,58 +759,27 @@
|
||||
</div>
|
||||
</ConfirmDialog>
|
||||
|
||||
<ConfirmDialog
|
||||
:open="deleteDialogOpen"
|
||||
:badge="deleteActionLabel"
|
||||
badge-tone="danger"
|
||||
:title="deleteDialogTitle"
|
||||
:description="deleteDialogDescription"
|
||||
cancel-text="取消"
|
||||
confirm-text="确认删除"
|
||||
busy-text="删除中..."
|
||||
confirm-tone="danger"
|
||||
confirm-icon="mdi mdi-trash-can-outline"
|
||||
:busy="deleteBusy"
|
||||
@close="closeDeleteDialog"
|
||||
@confirm="confirmDeleteRequest"
|
||||
/>
|
||||
<TravelRequestDeleteDialog :open="deleteDialogOpen" :badge="deleteActionLabel" :title="deleteDialogTitle" :description="deleteDialogDescription" :busy="deleteBusy" @close="closeDeleteDialog" @confirm="confirmDeleteRequest" />
|
||||
|
||||
<ConfirmDialog
|
||||
<TravelRequestApprovalDialog
|
||||
:open="approveConfirmDialogOpen"
|
||||
:badge="approvalConfirmBadge"
|
||||
badge-tone="info"
|
||||
:title="approveConfirmTitle"
|
||||
:description="approvalConfirmDescription"
|
||||
cancel-text="返回核对"
|
||||
:confirm-text="approveConfirmText"
|
||||
:busy-text="approveBusyText"
|
||||
confirm-tone="primary"
|
||||
confirm-icon="mdi mdi-check-circle-outline"
|
||||
:busy="approveBusy"
|
||||
:document-no="request.documentNo || request.id"
|
||||
:node="request.node"
|
||||
:summary-label="approvalConfirmSummaryLabel"
|
||||
:next-stage="approvalNextStage"
|
||||
:opinion-title="approvalOpinionTitle"
|
||||
:opinion="leaderOpinion"
|
||||
@close="closeApproveConfirmDialog"
|
||||
@confirm="confirmApproveRequest"
|
||||
>
|
||||
<div class="submit-confirm-summary" aria-label="领导审批通过摘要">
|
||||
<div class="submit-confirm-row">
|
||||
<span>单据编号</span>
|
||||
<strong>{{ request.documentNo || request.id }}</strong>
|
||||
</div>
|
||||
<div class="submit-confirm-row">
|
||||
<span>当前节点</span>
|
||||
<strong>{{ request.node }}</strong>
|
||||
</div>
|
||||
<div class="submit-confirm-row">
|
||||
<span>{{ approvalConfirmSummaryLabel }}</span>
|
||||
<strong>{{ approvalNextStage }}</strong>
|
||||
</div>
|
||||
<div class="submit-confirm-row">
|
||||
<span>{{ approvalOpinionTitle }}</span>
|
||||
<strong>{{ leaderOpinion.trim() || '未填写' }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</ConfirmDialog>
|
||||
/>
|
||||
|
||||
<ReturnReasonDialog
|
||||
<TravelRequestReturnDialog
|
||||
:open="returnDialogOpen"
|
||||
:title="`确认退回 ${request.id} 吗?`"
|
||||
:description="returnDialogDescription"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import TableLoadingState from '../../components/shared/TableLoadingState.vue'
|
||||
import TableEmptyState from '../../components/shared/TableEmptyState.vue'
|
||||
@@ -102,7 +102,6 @@ export default {
|
||||
const activeTypeFilter = ref(ARCHIVE_FILTER_ALL)
|
||||
const activeDepartmentFilter = ref(ARCHIVE_FILTER_ALL)
|
||||
const activeArchiveMonthFilter = ref(ARCHIVE_FILTER_ALL)
|
||||
const openFilterKey = ref('')
|
||||
const selectedClaimId = ref('')
|
||||
const listKeyword = ref('')
|
||||
const rows = ref([])
|
||||
@@ -118,7 +117,7 @@ export default {
|
||||
const departmentFilterLabel = computed(() => resolveFilterLabel(departmentFilterOptions.value, activeDepartmentFilter.value, '所属部门'))
|
||||
const archiveMonthFilterLabel = computed(() => resolveFilterLabel(archiveMonthFilterOptions.value, activeArchiveMonthFilter.value, '归档月份'))
|
||||
|
||||
const filterDropdowns = computed(() => [
|
||||
const filterMenus = computed(() => [
|
||||
{
|
||||
key: 'risk',
|
||||
label: riskFilterLabel.value,
|
||||
@@ -210,7 +209,6 @@ export default {
|
||||
activeDepartmentFilter.value = ARCHIVE_FILTER_ALL
|
||||
activeArchiveMonthFilter.value = ARCHIVE_FILTER_ALL
|
||||
listKeyword.value = ''
|
||||
openFilterKey.value = ''
|
||||
}
|
||||
|
||||
function handleEmptyAction() {
|
||||
@@ -222,10 +220,6 @@ export default {
|
||||
resetListFilters()
|
||||
}
|
||||
|
||||
function toggleFilterDropdown(key) {
|
||||
openFilterKey.value = openFilterKey.value === key ? '' : key
|
||||
}
|
||||
|
||||
function selectFilterValue(key, value) {
|
||||
if (key === 'risk') {
|
||||
activeRiskFilter.value = value
|
||||
@@ -237,18 +231,6 @@ export default {
|
||||
activeArchiveMonthFilter.value = value
|
||||
}
|
||||
|
||||
openFilterKey.value = ''
|
||||
}
|
||||
|
||||
function handleDocumentClick(event) {
|
||||
const target = event.target
|
||||
if (!(target instanceof Element)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!target.closest('.archive-dropdown-filter')) {
|
||||
openFilterKey.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
function closeSelectedDetail() {
|
||||
@@ -278,14 +260,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleDocumentClick)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', handleDocumentClick)
|
||||
})
|
||||
|
||||
void reload()
|
||||
|
||||
return {
|
||||
@@ -293,11 +267,10 @@ export default {
|
||||
archiveEmptyState,
|
||||
closeSelectedDetail,
|
||||
error,
|
||||
filterDropdowns,
|
||||
filterMenus,
|
||||
handleEmptyAction,
|
||||
listKeyword,
|
||||
loading,
|
||||
openFilterKey,
|
||||
reload,
|
||||
resetListFilters,
|
||||
rows,
|
||||
@@ -305,7 +278,6 @@ export default {
|
||||
selectedRow,
|
||||
showEmpty,
|
||||
tabs,
|
||||
toggleFilterDropdown,
|
||||
visibleRows
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import AuditAssetList from '../../components/audit/AuditAssetList.vue'
|
||||
import AuditJsonRiskRuleDetail from '../../components/audit/AuditJsonRiskRuleDetail.vue'
|
||||
import AuditRuleDialogs from '../../components/audit/AuditRuleDialogs.vue'
|
||||
import AuditSpreadsheetChangeDrawer from '../../components/audit/AuditSpreadsheetChangeDrawer.vue'
|
||||
import AuditSpreadsheetRuleDetail from '../../components/audit/AuditSpreadsheetRuleDetail.vue'
|
||||
import AuditVersionTimelineDrawer from '../../components/audit/AuditVersionTimelineDrawer.vue'
|
||||
import { fetchEmployees } from '../../services/employees.js'
|
||||
import RiskRuleFlowDiagram from '../../components/shared/RiskRuleFlowDiagram.vue'
|
||||
import RiskRuleTestDialog from '../../components/shared/RiskRuleTestDialog.vue'
|
||||
import TableLoadingState from '../../components/shared/TableLoadingState.vue'
|
||||
import TableEmptyState from '../../components/shared/TableEmptyState.vue'
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
import {
|
||||
@@ -77,11 +79,13 @@ import {
|
||||
export default {
|
||||
name: 'AuditView',
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
RiskRuleFlowDiagram,
|
||||
RiskRuleTestDialog,
|
||||
TableLoadingState,
|
||||
TableEmptyState
|
||||
AuditAssetList,
|
||||
AuditJsonRiskRuleDetail,
|
||||
AuditRuleDialogs,
|
||||
AuditSpreadsheetChangeDrawer,
|
||||
AuditSpreadsheetRuleDetail,
|
||||
AuditVersionTimelineDrawer,
|
||||
TableLoadingState
|
||||
},
|
||||
emits: ['detail-open-change'],
|
||||
setup(_, { emit }) {
|
||||
@@ -115,6 +119,10 @@ export default {
|
||||
const reviewSubmitReviewer = ref('')
|
||||
const reviewSubmitReviewerLoading = ref(false)
|
||||
const reviewSubmitReviewerOptions = ref([])
|
||||
const riskRuleAttachmentOptions = [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false }
|
||||
]
|
||||
const riskRuleCreateOpen = ref(false)
|
||||
const riskRuleCreateForm = ref(createDefaultRiskRuleForm())
|
||||
const riskRuleTestOpen = ref(false)
|
||||
@@ -466,7 +474,7 @@ export default {
|
||||
icon: hasFilters ? 'mdi mdi-tune-variant' : 'mdi mdi-view-grid-outline',
|
||||
actionLabel: hasFilters ? '清空筛选' : '',
|
||||
actionIcon: hasFilters ? 'mdi mdi-filter-remove-outline' : '',
|
||||
tone: hasFilters ? 'emerald' : 'slate',
|
||||
tone: hasFilters ? 'primary' : 'slate',
|
||||
artLabel: hasFilters ? 'FILTER' : 'QUEUE',
|
||||
tips: hasFilters
|
||||
? [
|
||||
@@ -956,7 +964,7 @@ export default {
|
||||
if (!canUploadSpreadsheet.value) {
|
||||
return
|
||||
}
|
||||
spreadsheetUploadInput.value?.click()
|
||||
spreadsheetUploadInput.value?.click?.()
|
||||
}
|
||||
|
||||
async function downloadSpreadsheetFile() {
|
||||
@@ -1003,9 +1011,7 @@ export default {
|
||||
toast(error?.message || '规则表内容导入失败,请稍后重试。')
|
||||
} finally {
|
||||
actionState.value = ''
|
||||
if (spreadsheetUploadInput.value) {
|
||||
spreadsheetUploadInput.value.value = ''
|
||||
}
|
||||
spreadsheetUploadInput.value?.reset?.()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1916,6 +1922,7 @@ export default {
|
||||
reviewSubmitReviewer,
|
||||
reviewSubmitReviewerLoading,
|
||||
reviewSubmitReviewerOptions,
|
||||
riskRuleAttachmentOptions,
|
||||
riskRuleCreateOpen,
|
||||
riskRuleCreateForm,
|
||||
riskRuleCreateBusy,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import BudgetTrendChart from '../../components/charts/BudgetTrendChart.vue'
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import { createBudgetAllocation, fetchBudgetSummary } from '../../services/budgets.js'
|
||||
import { fetchEmployeeMeta } from '../../services/employees.js'
|
||||
import {
|
||||
@@ -177,7 +178,8 @@ export default {
|
||||
},
|
||||
components: {
|
||||
BudgetTrendChart,
|
||||
ConfirmDialog
|
||||
ConfirmDialog,
|
||||
EnterpriseSelect
|
||||
},
|
||||
setup(props) {
|
||||
const departments = ref(FALLBACK_DEPARTMENTS)
|
||||
@@ -215,6 +217,14 @@ export default {
|
||||
const isDepartmentBudgetMonitor = computed(
|
||||
() => isBudgetMonitorUser(props.currentUser) && !canSwitchDepartments.value && !isExecutiveUser(props.currentUser)
|
||||
)
|
||||
const yearOptions = BUDGET_YEAR_OPTIONS.map((year) => ({ label: `${year}年度`, value: year }))
|
||||
const budgetPageSizeOptions = BUDGET_PAGE_SIZE_OPTIONS.map((size) => ({ label: `${size} 条/页`, value: size }))
|
||||
const departmentOptions = computed(() =>
|
||||
departments.value.map((department) => ({
|
||||
label: department.name,
|
||||
value: department.code
|
||||
}))
|
||||
)
|
||||
|
||||
const activeDepartment = computed(() =>
|
||||
departments.value.find((item) => item.code === activeDepartmentCode.value) || departments.value[0]
|
||||
@@ -273,7 +283,7 @@ export default {
|
||||
value: `¥${currency(totals.value.total)}`,
|
||||
yoy: comparison('+8.42%', 'up'),
|
||||
mom: comparison('+2.16%', 'up'),
|
||||
tone: 'green',
|
||||
tone: 'primary',
|
||||
icon: 'mdi mdi-wallet-outline'
|
||||
},
|
||||
{
|
||||
@@ -281,7 +291,7 @@ export default {
|
||||
value: `¥${currency(totals.value.used)}`,
|
||||
yoy: comparison('+12.68%', 'up'),
|
||||
mom: comparison('+4.35%', 'up'),
|
||||
tone: 'blue',
|
||||
tone: 'info',
|
||||
icon: 'mdi mdi-chart-line'
|
||||
},
|
||||
{
|
||||
@@ -289,7 +299,7 @@ export default {
|
||||
value: `¥${currency(totals.value.occupied)}`,
|
||||
yoy: comparison('+6.37%', 'up'),
|
||||
mom: comparison('-1.84%', 'down'),
|
||||
tone: 'orange',
|
||||
tone: 'warning',
|
||||
icon: 'mdi mdi-briefcase-check-outline'
|
||||
},
|
||||
{
|
||||
@@ -297,7 +307,7 @@ export default {
|
||||
value: `¥${currency(totals.value.left)}`,
|
||||
yoy: comparison('-3.26%', 'down'),
|
||||
mom: comparison('-2.08%', 'down'),
|
||||
tone: 'green',
|
||||
tone: 'primary',
|
||||
icon: 'mdi mdi-cash'
|
||||
}
|
||||
])
|
||||
@@ -612,7 +622,7 @@ export default {
|
||||
budgetPage: currentBudgetPage,
|
||||
budgetPageNumbers,
|
||||
budgetPageSize,
|
||||
budgetPageSizeOptions: BUDGET_PAGE_SIZE_OPTIONS,
|
||||
budgetPageSizeOptions,
|
||||
canEditBudget,
|
||||
canSwitchDepartments,
|
||||
closeBudgetEditDialog,
|
||||
@@ -633,6 +643,7 @@ export default {
|
||||
confirmDeleteRow,
|
||||
cancelDeleteRow,
|
||||
cancelSaveBudget,
|
||||
departmentOptions,
|
||||
requestSaveBudget,
|
||||
statusOptions: BUDGET_STATUS_OPTIONS,
|
||||
statuses: ['全部', '正常', '预警', '管控'],
|
||||
@@ -645,6 +656,7 @@ export default {
|
||||
visibleDepartments,
|
||||
warningOptions: BUDGET_WARNING_OPTIONS,
|
||||
warnings,
|
||||
yearOptions,
|
||||
years: BUDGET_YEAR_OPTIONS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import TableLoadingState from '../../components/shared/TableLoadingState.vue'
|
||||
import TableEmptyState from '../../components/shared/TableEmptyState.vue'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
@@ -438,6 +439,7 @@ export default {
|
||||
name: 'EmployeeManagementView',
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
EnterpriseSelect,
|
||||
TableLoadingState,
|
||||
TableEmptyState
|
||||
},
|
||||
@@ -457,7 +459,7 @@ export default {
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOpen = ref(false)
|
||||
const pageSizeOptions = pageSizes.map((size) => ({ label: `${size} 条/页`, value: size }))
|
||||
const actionState = ref('')
|
||||
const loading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
@@ -713,7 +715,7 @@ export default {
|
||||
icon: hasEmployeeFilters.value ? 'mdi mdi-account-search-outline' : 'mdi mdi-badge-account-horizontal-outline',
|
||||
actionLabel: hasEmployeeFilters.value ? '清空筛选' : '查看全部员工',
|
||||
actionIcon: hasEmployeeFilters.value ? 'mdi mdi-filter-remove-outline' : 'mdi mdi-format-list-bulleted',
|
||||
tone: hasEmployeeFilters.value ? 'emerald' : 'slate',
|
||||
tone: hasEmployeeFilters.value ? 'primary' : 'slate',
|
||||
artLabel: hasEmployeeFilters.value ? 'FILTER' : 'STATUS',
|
||||
tips: hasEmployeeFilters.value
|
||||
? ['关键词、部门、职级和角色条件会叠加生效', '也可以直接搜索姓名、工号或岗位']
|
||||
@@ -791,7 +793,6 @@ export default {
|
||||
|
||||
watch(filteredEmployees, () => {
|
||||
currentPage.value = 1
|
||||
pageSizeOpen.value = false
|
||||
})
|
||||
|
||||
function resetFilters() {
|
||||
@@ -801,7 +802,6 @@ export default {
|
||||
selectedRole.value = ''
|
||||
activeTab.value = DEFAULT_STATUS_TABS[0]
|
||||
activeFilterPopover.value = ''
|
||||
pageSizeOpen.value = false
|
||||
}
|
||||
|
||||
function handleEmployeeEmptyAction() {
|
||||
@@ -815,14 +815,9 @@ export default {
|
||||
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
function togglePageSizeOpen() {
|
||||
pageSizeOpen.value = !pageSizeOpen.value
|
||||
}
|
||||
|
||||
function toggleFilterPopover(name) {
|
||||
activeFilterPopover.value = activeFilterPopover.value === name ? '' : name
|
||||
}
|
||||
@@ -852,7 +847,6 @@ export default {
|
||||
|
||||
if (!(target instanceof Element)) {
|
||||
closeFilterPopover()
|
||||
pageSizeOpen.value = false
|
||||
return
|
||||
}
|
||||
|
||||
@@ -868,13 +862,8 @@ export default {
|
||||
closeDepartmentPicker()
|
||||
}
|
||||
|
||||
if (!target.closest('.page-size-wrap')) {
|
||||
pageSizeOpen.value = false
|
||||
}
|
||||
|
||||
if (
|
||||
target.closest('.picker-filter') ||
|
||||
target.closest('.page-size-wrap') ||
|
||||
target.closest('.manager-picker') ||
|
||||
target.closest('.department-picker')
|
||||
) {
|
||||
@@ -1437,7 +1426,7 @@ export default {
|
||||
currentPage,
|
||||
pageSize,
|
||||
pageSizes,
|
||||
pageSizeOpen,
|
||||
pageSizeOptions,
|
||||
departmentOptions,
|
||||
gradeOptions,
|
||||
roleFilterOptions,
|
||||
@@ -1475,7 +1464,6 @@ export default {
|
||||
disableDialogOpen,
|
||||
disableEmployeeAccount,
|
||||
changePageSize,
|
||||
togglePageSizeOpen,
|
||||
toggleFilterPopover,
|
||||
closeFilterPopover,
|
||||
selectFilter,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ref } from 'vue'
|
||||
import { testModelConnectivity } from '../../services/settings.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
|
||||
const MODEL_SECRET_MASK = '********'
|
||||
|
||||
@@ -101,6 +102,9 @@ function isModelSecretMask(value) {
|
||||
|
||||
export default {
|
||||
name: 'LlmSettingsPanel',
|
||||
components: {
|
||||
EnterpriseSelect
|
||||
},
|
||||
props: {
|
||||
llmForm: {
|
||||
type: Object,
|
||||
|
||||
@@ -11,7 +11,7 @@ export default {
|
||||
const showPassword = ref(false)
|
||||
|
||||
const features = [
|
||||
{ title: '智能审单', desc: 'AI 自动识别票据与规则,提升准确率与效率', icon: 'mdi mdi-file-document-outline', tone: 'green' },
|
||||
{ title: '智能审单', desc: 'AI 自动识别票据与规则,提升准确率与效率', icon: 'mdi mdi-file-document-outline', tone: 'primary' },
|
||||
{ title: '异常预警', desc: '多维风险识别与预警,主动防控风险', icon: 'mdi mdi-bell-outline', tone: 'red' },
|
||||
{ title: 'SLA 监控', desc: '实时监控服务水平协议,保障审批及时性', icon: 'mdi mdi-sync', tone: 'blue' }
|
||||
]
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
import LogTrendChart from '../../components/charts/LogTrendChart.vue'
|
||||
import DonutChart from '../../components/charts/DonutChart.vue'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import TableLoadingState from '../../components/shared/TableLoadingState.vue'
|
||||
import { fetchAgentRuns } from '../../services/agentAssets.js'
|
||||
import { fetchSystemLogEntries } from '../../services/systemLogs.js'
|
||||
@@ -221,6 +222,7 @@ export default {
|
||||
components: {
|
||||
LogTrendChart,
|
||||
DonutChart,
|
||||
EnterpriseSelect,
|
||||
TableLoadingState
|
||||
},
|
||||
emits: ['summary-change'],
|
||||
@@ -237,20 +239,28 @@ export default {
|
||||
const systemLevelFilter = ref('')
|
||||
const systemEventTypeFilter = ref('')
|
||||
const systemLogEntries = ref([])
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOpen = ref(false)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOptions = pageSizes.map((size) => ({ label: `${size} 条/页`, value: size }))
|
||||
let pollTimer = 0
|
||||
|
||||
const isAdmin = computed(() => isManagerUser(currentUser.value))
|
||||
const filteredHermesRuns = computed(() => hermesRuns.value)
|
||||
const systemLevelOptions = computed(() =>
|
||||
Array.from(new Set(systemLogEntries.value.map((entry) => entry.level).filter(Boolean)))
|
||||
)
|
||||
const systemEventTypeOptions = computed(() =>
|
||||
Array.from(new Set(systemLogEntries.value.map((entry) => entry.event_type).filter(Boolean)))
|
||||
)
|
||||
const systemLevelOptions = computed(() =>
|
||||
Array.from(new Set(systemLogEntries.value.map((entry) => entry.level).filter(Boolean)))
|
||||
)
|
||||
const systemEventTypeOptions = computed(() =>
|
||||
Array.from(new Set(systemLogEntries.value.map((entry) => entry.event_type).filter(Boolean)))
|
||||
)
|
||||
const systemLevelFilterOptions = computed(() => [
|
||||
{ label: '全部', value: '' },
|
||||
...systemLevelOptions.value
|
||||
])
|
||||
const systemEventTypeFilterOptions = computed(() => [
|
||||
{ label: '全部', value: '' },
|
||||
...systemEventTypeOptions.value
|
||||
])
|
||||
const filteredSystemLogEntries = computed(() => {
|
||||
const keyword = systemSearchKeyword.value.trim().toLowerCase()
|
||||
return systemLogEntries.value.filter((entry) => {
|
||||
@@ -330,11 +340,10 @@ export default {
|
||||
return filteredSystemLogEntries.value.slice(start, start + pageSize.value)
|
||||
})
|
||||
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
async function loadHermesRuns() {
|
||||
if (!isAdmin.value) {
|
||||
@@ -456,8 +465,8 @@ export default {
|
||||
loadSystemLogs,
|
||||
currentPage,
|
||||
pageSize,
|
||||
pageSizeOpen,
|
||||
pageSizes,
|
||||
pageSizes,
|
||||
pageSizeOptions,
|
||||
resolveLevelTone,
|
||||
resolveRunLevel,
|
||||
resolveRunModuleLabel,
|
||||
@@ -472,10 +481,12 @@ export default {
|
||||
runningRunCount,
|
||||
selectRun,
|
||||
selectSystemLog,
|
||||
systemEventTypeFilter,
|
||||
systemEventTypeOptions,
|
||||
systemLevelFilter,
|
||||
systemLevelOptions,
|
||||
systemEventTypeFilter,
|
||||
systemEventTypeFilterOptions,
|
||||
systemEventTypeOptions,
|
||||
systemLevelFilter,
|
||||
systemLevelFilterOptions,
|
||||
systemLevelOptions,
|
||||
systemLogEntries,
|
||||
systemLogLoading,
|
||||
systemSearchKeyword,
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
|
||||
export default {
|
||||
name: 'MailSettingsPanel',
|
||||
components: {
|
||||
EnterpriseSelect
|
||||
},
|
||||
props: {
|
||||
mailForm: {
|
||||
type: Object,
|
||||
@@ -7,6 +12,12 @@ export default {
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const encryptionOptions = [
|
||||
{ label: 'SSL/TLS', value: 'SSL/TLS' },
|
||||
{ label: 'STARTTLS', value: 'STARTTLS' },
|
||||
{ label: '无', value: 'None' }
|
||||
]
|
||||
|
||||
function toggleField(field) {
|
||||
if (props.mailForm) {
|
||||
props.mailForm[field] = !props.mailForm[field]
|
||||
@@ -14,6 +25,7 @@ export default {
|
||||
}
|
||||
|
||||
return {
|
||||
encryptionOptions,
|
||||
toggleField
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,11 @@ export default {
|
||||
}
|
||||
|
||||
const demoDepartments = [
|
||||
{ name: '销售部', amount: 182000, color: '#10b981' },
|
||||
{ name: '研发中心', amount: 146000, color: '#3b82f6' },
|
||||
{ name: '市场部', amount: 96000, color: '#f59e0b' },
|
||||
{ name: '运营部', amount: 68600, color: '#8b5cf6' },
|
||||
{ name: '行政部', amount: 48300, color: '#3b82f6' }
|
||||
{ name: '销售部', amount: 182000, color: 'var(--theme-primary)' },
|
||||
{ name: '研发中心', amount: 146000, color: 'var(--chart-blue)' },
|
||||
{ name: '市场部', amount: 96000, color: 'var(--chart-amber)' },
|
||||
{ name: '运营部', amount: 68600, color: 'var(--chart-purple)' },
|
||||
{ name: '行政部', amount: 48300, color: 'var(--chart-blue)' }
|
||||
]
|
||||
|
||||
const formatCompact = (value) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import TableLoadingState from '../../components/shared/TableLoadingState.vue'
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
@@ -86,6 +87,7 @@ export default {
|
||||
name: 'PoliciesView',
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
EnterpriseSelect,
|
||||
TableLoadingState
|
||||
},
|
||||
emits: ['summary-change'],
|
||||
@@ -95,13 +97,13 @@ export default {
|
||||
|
||||
const documentSearch = ref('')
|
||||
const activeFolder = ref('')
|
||||
const folders = ref([])
|
||||
const documents = ref([])
|
||||
const selectedDocument = ref(null)
|
||||
const pageSizeOpen = ref(false)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const folders = ref([])
|
||||
const documents = ref([])
|
||||
const selectedDocument = ref(null)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOptions = pageSizes.map((size) => ({ label: `${size} 条/页`, value: size }))
|
||||
const loading = ref(false)
|
||||
const uploadInput = ref(null)
|
||||
const uploading = ref(false)
|
||||
@@ -558,11 +560,10 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
function closePreview() {
|
||||
selectedDocument.value = null
|
||||
@@ -586,12 +587,11 @@ export default {
|
||||
currentPreviewPageIndex.value = index
|
||||
}
|
||||
|
||||
watch(filteredDocuments, () => {
|
||||
currentPage.value = 1
|
||||
pageSizeOpen.value = false
|
||||
|
||||
if (selectedDocument.value && !filteredDocuments.value.some((doc) => doc.id === selectedDocument.value.id)) {
|
||||
closePreview()
|
||||
watch(filteredDocuments, () => {
|
||||
currentPage.value = 1
|
||||
|
||||
if (selectedDocument.value && !filteredDocuments.value.some((doc) => doc.id === selectedDocument.value.id)) {
|
||||
closePreview()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -650,9 +650,9 @@ export default {
|
||||
knowledgeSyncButtonLabel,
|
||||
knowledgeSyncHint,
|
||||
loading,
|
||||
pageSize,
|
||||
pageSizeOpen,
|
||||
pageSizes,
|
||||
pageSize,
|
||||
pageSizeOptions,
|
||||
pageSizes,
|
||||
onlyOfficeError,
|
||||
onlyOfficeHostId,
|
||||
onlyOfficeLoading,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import TableLoadingState from '../../components/shared/TableLoadingState.vue'
|
||||
import TableEmptyState from '../../components/shared/TableEmptyState.vue'
|
||||
import { normalizeRequestForUi } from '../../utils/requestViewModel.js'
|
||||
@@ -12,6 +13,7 @@ function extractRowDate(value) {
|
||||
export default {
|
||||
name: 'RequestsView',
|
||||
components: {
|
||||
EnterpriseSelect,
|
||||
TableLoadingState,
|
||||
TableEmptyState
|
||||
},
|
||||
@@ -61,11 +63,10 @@ export default {
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const pageSizes = [10, 20, 50]
|
||||
const pageSizeOpen = ref(false)
|
||||
const pageSizeOptions = pageSizes.map((size) => ({ label: `${size} 条/页`, value: size }))
|
||||
|
||||
function changePageSize(size) {
|
||||
pageSize.value = size
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
@@ -132,7 +133,7 @@ export default {
|
||||
icon: 'mdi mdi-receipt-text-plus-outline',
|
||||
actionLabel: '',
|
||||
actionIcon: '',
|
||||
tone: 'emerald',
|
||||
tone: 'theme',
|
||||
artLabel: 'CLAIM',
|
||||
tips: ['保存草稿后会自动回到这里', '支持草稿、待提交、审批中和已完成全流程管理']
|
||||
}
|
||||
@@ -163,7 +164,6 @@ export default {
|
||||
rangeEnd.value = ''
|
||||
appliedStart.value = ''
|
||||
appliedEnd.value = ''
|
||||
pageSizeOpen.value = false
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ export default {
|
||||
currentPage,
|
||||
pageSize,
|
||||
pageSizes,
|
||||
pageSizeOpen,
|
||||
pageSizeOptions,
|
||||
changePageSize,
|
||||
filteredRows,
|
||||
totalCount,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import HermesEmployeeSettingsPanel from '../HermesEmployeeSettingsPanel.vue'
|
||||
import LlmSettingsPanel from '../LlmSettingsPanel.vue'
|
||||
import MailSettingsPanel from '../MailSettingsPanel.vue'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import { useSettings } from '../../composables/useSettings.js'
|
||||
|
||||
export default {
|
||||
name: 'SettingsView',
|
||||
components: {
|
||||
HermesEmployeeSettingsPanel,
|
||||
EnterpriseSelect,
|
||||
LlmSettingsPanel,
|
||||
MailSettingsPanel
|
||||
},
|
||||
@@ -18,4 +20,3 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import TravelReimbursementInsightPanel from '../../components/travel/TravelReimbursementInsightPanel.vue'
|
||||
import TravelReimbursementMessageItem from '../../components/travel/TravelReimbursementMessageItem.vue'
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
import { useTravelReimbursementFlow } from './useTravelReimbursementFlow.js'
|
||||
@@ -501,7 +503,9 @@ function buildReviewMainMessageText(message) {
|
||||
export default {
|
||||
name: 'TravelReimbursementCreateView',
|
||||
components: {
|
||||
ConfirmDialog
|
||||
ConfirmDialog,
|
||||
TravelReimbursementInsightPanel,
|
||||
TravelReimbursementMessageItem
|
||||
},
|
||||
props: {
|
||||
initialPrompt: {
|
||||
@@ -2109,8 +2113,126 @@ export default {
|
||||
await handleSaveDraftDirectly(message, 'save_draft')
|
||||
}
|
||||
|
||||
const messageItemUi = computed(() => ({
|
||||
ASSISTANT_DISPLAY_NAME,
|
||||
aiAvatar,
|
||||
userAvatar,
|
||||
submitting: submitting.value,
|
||||
reviewActionBusy: reviewActionBusy.value,
|
||||
sessionSwitchBusy: sessionSwitchBusy.value,
|
||||
applicationPreviewEditor: applicationPreviewEditor.value,
|
||||
buildMessageBubbleClass,
|
||||
buildReviewMainMessageText,
|
||||
renderMarkdown,
|
||||
handleAssistantMarkdownClick,
|
||||
resolveApplicationPreviewRows,
|
||||
resolveApplicationPreviewEditorControl,
|
||||
resolveApplicationPreviewEditorOptions,
|
||||
isApplicationPreviewEditing,
|
||||
openApplicationPreviewEditor,
|
||||
commitApplicationPreviewEditor,
|
||||
handleApplicationPreviewEditorKeydown,
|
||||
buildApplicationPreviewFooterText,
|
||||
runWelcomeQuickAction: runShortcut,
|
||||
handleSuggestedAction,
|
||||
isSuggestedActionSelected,
|
||||
buildExpenseQueryWindowLabel,
|
||||
buildExpenseQueryHint,
|
||||
getExpenseQueryActivePage,
|
||||
getExpenseQueryTotalPages,
|
||||
getExpenseQueryVisibleRecords,
|
||||
handleExpenseQueryRecordClick,
|
||||
appendExpenseQueryRiskToConversation,
|
||||
shiftExpenseQueryPage,
|
||||
setExpenseQueryPage,
|
||||
buildReviewPlainFollowupForMessage,
|
||||
canUseInlineSaveDraft,
|
||||
handleInlineSaveDraft,
|
||||
buildReviewNextStepRichCopyForMessage,
|
||||
resolveReviewFooterActions,
|
||||
handleReviewAction,
|
||||
buildReviewPrimaryButtonLabel
|
||||
}))
|
||||
|
||||
const insightPanelUi = computed(() => ({
|
||||
showInsightPanel: showInsightPanel.value,
|
||||
isKnowledgeSession: isKnowledgeSession.value,
|
||||
activeReviewPayload: activeReviewPayload.value,
|
||||
isReviewFlowDrawer: isReviewFlowDrawer.value,
|
||||
currentInsight: currentInsight.value,
|
||||
currentIntentLabel: currentIntentLabel.value,
|
||||
reviewDrawerTitle: reviewDrawerTitle.value,
|
||||
reviewOverviewDrawerAvailable: reviewOverviewDrawerAvailable.value,
|
||||
isReviewOverviewDrawer: isReviewOverviewDrawer.value,
|
||||
submitting: submitting.value,
|
||||
reviewActionBusy: reviewActionBusy.value,
|
||||
switchToReviewOverviewDrawer,
|
||||
reviewDocumentDrawerAvailable: reviewDocumentDrawerAvailable.value,
|
||||
isReviewDocumentDrawer: isReviewDocumentDrawer.value,
|
||||
toggleReviewDocumentDrawer,
|
||||
reviewDocumentDrawerIcon: reviewDocumentDrawerIcon.value,
|
||||
reviewRiskDrawerAvailable: reviewRiskDrawerAvailable.value,
|
||||
isReviewRiskDrawer: isReviewRiskDrawer.value,
|
||||
toggleReviewRiskDrawer,
|
||||
reviewRiskDrawerIcon: reviewRiskDrawerIcon.value,
|
||||
reviewFlowDrawerAvailable: reviewFlowDrawerAvailable.value,
|
||||
flowOverallStatusTone: flowOverallStatusTone.value,
|
||||
toggleReviewFlowDrawer,
|
||||
reviewFlowDrawerIcon: reviewFlowDrawerIcon.value,
|
||||
activeSessionType: activeSessionType.value,
|
||||
reviewDrawerMode: reviewDrawerMode.value,
|
||||
hotKnowledgeQuestions,
|
||||
deleteSessionBusy: deleteSessionBusy.value,
|
||||
sessionSwitchBusy: sessionSwitchBusy.value,
|
||||
askHotKnowledgeQuestion,
|
||||
resolveKnowledgeRankTone,
|
||||
resolveKnowledgeRankLabel,
|
||||
flowOverallStatusText: flowOverallStatusText.value,
|
||||
flowTotalDurationText: flowTotalDurationText.value,
|
||||
flowRunId: flowRunId.value,
|
||||
flowRefreshBusy: flowRefreshBusy.value,
|
||||
refreshFlowRunDetail,
|
||||
flowSteps: flowSteps.value,
|
||||
resolveFlowStepStatusLabel,
|
||||
formatFlowStepDuration,
|
||||
resolveFlowStepDetail,
|
||||
reviewIntentText: reviewIntentText.value,
|
||||
reviewFactCards: reviewFactCards.value,
|
||||
reviewInlineEditorKey: reviewInlineEditorKey.value,
|
||||
reviewInlineErrors: reviewInlineErrors.value,
|
||||
reviewInlineForm: reviewInlineForm.value,
|
||||
DATE_INPUT_FORMAT,
|
||||
REVIEW_SCENE_OPTIONS,
|
||||
REVIEW_SCENE_OTHER_OPTION,
|
||||
clearInlineReviewFieldError,
|
||||
commitInlineReviewEditor,
|
||||
selectInlineScene,
|
||||
reviewInlinePendingFiles: reviewInlinePendingFiles.value,
|
||||
openInlineReviewEditor,
|
||||
reviewPanelConfidence: reviewPanelConfidence.value,
|
||||
reviewCategoryOptions: reviewCategoryOptions.value,
|
||||
selectReviewCategory,
|
||||
reviewSelectedOtherCategory: reviewSelectedOtherCategory.value,
|
||||
reviewOtherCategoryOpen: reviewOtherCategoryOpen.value,
|
||||
reviewOtherCategoryOptions: reviewOtherCategoryOptions.value,
|
||||
selectReviewOtherCategory,
|
||||
activeReviewDocumentIndex: activeReviewDocumentIndex.value,
|
||||
reviewDocumentCount: reviewDocumentCount.value,
|
||||
goReviewDocument,
|
||||
activeReviewDocument: activeReviewDocument.value,
|
||||
activeReviewDocumentPreview: activeReviewDocumentPreview.value,
|
||||
canPreviewActiveReviewDocument: canPreviewActiveReviewDocument.value,
|
||||
openActiveReviewDocumentPreview,
|
||||
reviewRiskSummary: reviewRiskSummary.value,
|
||||
reviewRiskItems: reviewRiskItems.value,
|
||||
appendReviewRiskBriefToConversation,
|
||||
reviewRiskEmpty: reviewRiskEmpty.value,
|
||||
reviewHasUnsavedChanges: reviewHasUnsavedChanges.value,
|
||||
saveInlineReviewChanges
|
||||
}))
|
||||
|
||||
return {
|
||||
emit, ASSISTANT_DISPLAY_NAME, aiAvatar, userAvatar, fileInputRef, composerTextareaRef, messageListRef, composerDraft, composerDatePickerOpen, composerDateMode, composerSingleDate, composerRangeStartDate, composerRangeEndDate, composerBusinessTimeTags, composerCanApplyDateSelection,
|
||||
emit, messageItemUi, insightPanelUi, ASSISTANT_DISPLAY_NAME, aiAvatar, userAvatar, fileInputRef, composerTextareaRef, messageListRef, composerDraft, composerDatePickerOpen, composerDateMode, composerSingleDate, composerRangeStartDate, composerRangeEndDate, composerBusinessTimeTags, composerCanApplyDateSelection,
|
||||
toggleComposerDatePicker, closeComposerDatePicker, setComposerDateMode, handleComposerDateInputChange, removeComposerBusinessTimeTag, flowSteps, flowRunId, flowRefreshBusy, completedFlowStepCount, flowOverallStatusTone, flowOverallStatusText, flowTotalDurationText,
|
||||
attachedFiles, composerFilesExpanded, visibleAttachedFiles, hiddenAttachedFileCount, submitting, sessionSwitchBusy, messages, currentInsight, linkedRequest, canSubmit, activeSessionType, isKnowledgeSession, hotKnowledgeQuestions,
|
||||
hasInsightPanelContent, showInsightPanel, insightPanelToggleLabel, assistantHeaderTitle, assistantHeaderDescription, composerPlaceholder, currentIntentLabel, canDeleteCurrentSession, latestReviewMessage, activeReviewPayload, activeReviewPanelScope, activeReviewFilePreviews, reviewDrawerMode, isReviewOverviewDrawer, isReviewDocumentDrawer, isReviewRiskDrawer, isReviewFlowDrawer,
|
||||
|
||||
@@ -2,8 +2,11 @@ import { computed, onBeforeUnmount, reactive, ref, watch } from 'vue'
|
||||
|
||||
import { useSystemState } from '../../composables/useSystemState.js'
|
||||
import { useToast } from '../../composables/useToast.js'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import ReturnReasonDialog from '../../components/shared/ReturnReasonDialog.vue'
|
||||
import TravelRequestApprovalDialog from '../../components/travel/TravelRequestApprovalDialog.vue'
|
||||
import TravelRequestDeleteDialog from '../../components/travel/TravelRequestDeleteDialog.vue'
|
||||
import TravelRequestReturnDialog from '../../components/travel/TravelRequestReturnDialog.vue'
|
||||
import {
|
||||
approveExpenseClaim,
|
||||
createExpenseClaimItem,
|
||||
@@ -358,7 +361,10 @@ export default {
|
||||
name: 'TravelRequestDetailView',
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
ReturnReasonDialog
|
||||
EnterpriseSelect,
|
||||
TravelRequestApprovalDialog,
|
||||
TravelRequestDeleteDialog,
|
||||
TravelRequestReturnDialog
|
||||
},
|
||||
props: {
|
||||
request: {
|
||||
|
||||
@@ -71,7 +71,7 @@ export const TAB_META = {
|
||||
tableColumns: RULE_TABLE_COLUMNS,
|
||||
showRuntimeColumn: false,
|
||||
showStatusColumn: false,
|
||||
badgeTone: 'emerald'
|
||||
badgeTone: 'primary'
|
||||
},
|
||||
riskRules: {
|
||||
assetType: 'rule',
|
||||
|
||||
@@ -346,7 +346,7 @@ export function resolveTabMeta(tabId, typeKey) {
|
||||
return {
|
||||
...TYPE_META.rules,
|
||||
typeKey: 'rules',
|
||||
badgeTone: 'emerald'
|
||||
badgeTone: 'primary'
|
||||
}
|
||||
}
|
||||
return TAB_META[typeKey]
|
||||
|
||||
Reference in New Issue
Block a user