feat: add skill center navigation and travel request detail view
- Refactor audit to skill center for skill management - Add TravelRequestDetailView for requests detail page - Update PersonalWorkbench with enhanced features - Add UI preview screenshots Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
BIN
UI/首页工作台.png
Normal file
BIN
UI/首页工作台.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 971 KiB |
37
src/App.vue
37
src/App.vue
@@ -24,7 +24,8 @@
|
|||||||
'workbench-main': activeView === 'workbench',
|
'workbench-main': activeView === 'workbench',
|
||||||
'requests-main': activeView === 'requests',
|
'requests-main': activeView === 'requests',
|
||||||
'approval-main': activeView === 'approval',
|
'approval-main': activeView === 'approval',
|
||||||
'policies-main': activeView === 'policies'
|
'policies-main': activeView === 'policies',
|
||||||
|
'audit-main': activeView === 'audit'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<TopBar
|
<TopBar
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<FilterBar
|
<FilterBar
|
||||||
v-if="activeView !== 'chat' && activeView !== 'overview' && activeView !== 'workbench' && activeView !== 'requests' && activeView !== 'approval' && activeView !== 'policies'"
|
v-if="activeView !== 'chat' && activeView !== 'overview' && activeView !== 'workbench' && activeView !== 'requests' && activeView !== 'approval' && activeView !== 'policies' && activeView !== 'audit'"
|
||||||
:compact="activeView === 'overview'"
|
:compact="activeView === 'overview'"
|
||||||
:filters="filters"
|
:filters="filters"
|
||||||
:ranges="ranges"
|
:ranges="ranges"
|
||||||
@@ -57,7 +58,8 @@
|
|||||||
'chat-workarea': activeView === 'chat',
|
'chat-workarea': activeView === 'chat',
|
||||||
'requests-workarea': activeView === 'requests',
|
'requests-workarea': activeView === 'requests',
|
||||||
'approval-workarea': activeView === 'approval',
|
'approval-workarea': activeView === 'approval',
|
||||||
'policies-workarea': activeView === 'policies'
|
'policies-workarea': activeView === 'policies',
|
||||||
|
'audit-workarea': activeView === 'audit'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<OverviewView
|
<OverviewView
|
||||||
@@ -96,15 +98,16 @@
|
|||||||
@reject-case="toast(`${activeCase?.id} 已转人工复核。`)"
|
@reject-case="toast(`${activeCase?.id} 已转人工复核。`)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TravelReimbursementCreateView
|
<TravelRequestDetailView
|
||||||
v-else-if="activeView === 'requests' && detailMode"
|
v-else-if="activeView === 'requests' && detailMode"
|
||||||
@back-to-requests="detailMode = false"
|
:request="selectedTravelRequest"
|
||||||
|
@back-to-requests="closeRequestDetail"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RequestsView
|
<RequestsView
|
||||||
v-else-if="activeView === 'requests'"
|
v-else-if="activeView === 'requests'"
|
||||||
:filtered-requests="filteredRequests"
|
:filtered-requests="filteredRequests"
|
||||||
@ask="detailMode = true"
|
@ask="openRequestDetail"
|
||||||
@approve="handleApprove"
|
@approve="handleApprove"
|
||||||
@reject="handleReject"
|
@reject="handleReject"
|
||||||
@create-request="openTravelCreate"
|
@create-request="openTravelCreate"
|
||||||
@@ -135,6 +138,7 @@ import OverviewView from './views/OverviewView.vue'
|
|||||||
import PersonalWorkbenchView from './views/PersonalWorkbenchView.vue'
|
import PersonalWorkbenchView from './views/PersonalWorkbenchView.vue'
|
||||||
import ChatView from './views/ChatView.vue'
|
import ChatView from './views/ChatView.vue'
|
||||||
import TravelReimbursementCreateView from './views/TravelReimbursementCreateView.vue'
|
import TravelReimbursementCreateView from './views/TravelReimbursementCreateView.vue'
|
||||||
|
import TravelRequestDetailView from './views/TravelRequestDetailView.vue'
|
||||||
import RequestsView from './views/RequestsView.vue'
|
import RequestsView from './views/RequestsView.vue'
|
||||||
import ApprovalCenterView from './views/ApprovalCenterView.vue'
|
import ApprovalCenterView from './views/ApprovalCenterView.vue'
|
||||||
import PoliciesView from './views/PoliciesView.vue'
|
import PoliciesView from './views/PoliciesView.vue'
|
||||||
@@ -150,6 +154,7 @@ import { documents } from './data/requests.js'
|
|||||||
const loggedIn = ref(false)
|
const loggedIn = ref(false)
|
||||||
const travelCreateMode = ref(false)
|
const travelCreateMode = ref(false)
|
||||||
const detailMode = ref(false)
|
const detailMode = ref(false)
|
||||||
|
const selectedTravelRequest = ref(null)
|
||||||
|
|
||||||
function handleLogin(credentials) {
|
function handleLogin(credentials) {
|
||||||
if (credentials.username && credentials.password) {
|
if (credentials.username && credentials.password) {
|
||||||
@@ -205,6 +210,7 @@ function handleReject(request) {
|
|||||||
function handleNavigate(view) {
|
function handleNavigate(view) {
|
||||||
travelCreateMode.value = false
|
travelCreateMode.value = false
|
||||||
detailMode.value = false
|
detailMode.value = false
|
||||||
|
selectedTravelRequest.value = null
|
||||||
setView(view)
|
setView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +221,8 @@ function handleOpenChat(request) {
|
|||||||
|
|
||||||
function openTravelCreate() {
|
function openTravelCreate() {
|
||||||
travelCreateMode.value = true
|
travelCreateMode.value = true
|
||||||
|
detailMode.value = false
|
||||||
|
selectedTravelRequest.value = null
|
||||||
activeView.value = 'chat'
|
activeView.value = 'chat'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +230,17 @@ function backToRequests() {
|
|||||||
travelCreateMode.value = false
|
travelCreateMode.value = false
|
||||||
activeView.value = 'requests'
|
activeView.value = 'requests'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openRequestDetail(request) {
|
||||||
|
selectedTravelRequest.value = request
|
||||||
|
detailMode.value = true
|
||||||
|
activeView.value = 'requests'
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeRequestDetail() {
|
||||||
|
detailMode.value = false
|
||||||
|
selectedTravelRequest.value = null
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -245,7 +264,8 @@ function backToRequests() {
|
|||||||
}
|
}
|
||||||
.main.requests-main,
|
.main.requests-main,
|
||||||
.main.approval-main,
|
.main.approval-main,
|
||||||
.main.policies-main {
|
.main.policies-main,
|
||||||
|
.main.audit-main {
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -257,7 +277,8 @@ function backToRequests() {
|
|||||||
}
|
}
|
||||||
.workarea.requests-workarea,
|
.workarea.requests-workarea,
|
||||||
.workarea.approval-workarea,
|
.workarea.approval-workarea,
|
||||||
.workarea.policies-workarea {
|
.workarea.policies-workarea,
|
||||||
|
.workarea.audit-workarea {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 20px 24px;
|
padding: 20px 24px;
|
||||||
|
|||||||
BIN
src/assets/robot-assistant.png
Normal file
BIN
src/assets/robot-assistant.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 937 KiB |
@@ -10,7 +10,7 @@
|
|||||||
<article class="panel assistant-hero">
|
<article class="panel assistant-hero">
|
||||||
<div class="assistant-visual" aria-hidden="true">
|
<div class="assistant-visual" aria-hidden="true">
|
||||||
<div class="assistant-core">
|
<div class="assistant-core">
|
||||||
<i class="mdi mdi-robot-happy-outline"></i>
|
<img class="assistant-image" :src="robotAssistant" alt="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -40,8 +40,11 @@
|
|||||||
<div class="workbench-grid">
|
<div class="workbench-grid">
|
||||||
<article class="panel list-panel">
|
<article class="panel list-panel">
|
||||||
<div class="section-head">
|
<div class="section-head">
|
||||||
|
<div class="title-with-badge">
|
||||||
<h3>今日待办</h3>
|
<h3>今日待办</h3>
|
||||||
<span class="count-chip">{{ todoItems.length }} 项</span>
|
<span class="alert-badge">{{ todoAlertCount }}</span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="link-action">查看全部 <i class="mdi mdi-chevron-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="list-body">
|
<div class="list-body">
|
||||||
@@ -52,7 +55,10 @@
|
|||||||
|
|
||||||
<div class="todo-copy">
|
<div class="todo-copy">
|
||||||
<strong>{{ item.title }}</strong>
|
<strong>{{ item.title }}</strong>
|
||||||
<p>{{ item.suggestion }}</p>
|
<p class="todo-advice">
|
||||||
|
<span class="todo-advice-label">{{ item.tipLabel }}</span>
|
||||||
|
<span class="todo-advice-text">{{ item.suggestion }}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="row-action" @click="emit('openAssistant')">{{ item.action }}</button>
|
<button type="button" class="row-action" @click="emit('openAssistant')">{{ item.action }}</button>
|
||||||
@@ -62,7 +68,10 @@
|
|||||||
|
|
||||||
<article class="panel list-panel">
|
<article class="panel list-panel">
|
||||||
<div class="section-head">
|
<div class="section-head">
|
||||||
|
<div class="title-with-badge">
|
||||||
<h3>报销进度</h3>
|
<h3>报销进度</h3>
|
||||||
|
<span class="alert-badge">{{ progressAlertCount }}</span>
|
||||||
|
</div>
|
||||||
<button type="button" class="link-action">查看全部 <i class="mdi mdi-chevron-right"></i></button>
|
<button type="button" class="link-action">查看全部 <i class="mdi mdi-chevron-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -73,13 +82,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="todo-copy progress-copy">
|
<div class="todo-copy progress-copy">
|
||||||
<div class="progress-main">
|
|
||||||
<strong>{{ item.title }}</strong>
|
<strong>{{ item.title }}</strong>
|
||||||
<strong class="amount">{{ item.amount }}</strong>
|
|
||||||
</div>
|
|
||||||
<p>提交时间:{{ item.date }}</p>
|
<p>提交时间:{{ item.date }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<strong class="progress-amount">{{ item.amount }}</strong>
|
||||||
<span class="progress-status" :class="item.tone">{{ item.status }}</span>
|
<span class="progress-status" :class="item.tone">{{ item.status }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,23 +101,15 @@
|
|||||||
|
|
||||||
<div class="policy-table">
|
<div class="policy-table">
|
||||||
<div class="policy-head policy-row">
|
<div class="policy-head policy-row">
|
||||||
<span>制度名称</span>
|
<span class="policy-title-cell">制度名称</span>
|
||||||
<span>摘要</span>
|
<span class="policy-summary-cell">摘要</span>
|
||||||
<span>发布日期</span>
|
<span class="policy-date-cell">发布日期</span>
|
||||||
<span>状态</span>
|
|
||||||
<span></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="item in policyItems" :key="item.name" class="policy-row">
|
<div v-for="item in policyItems" :key="item.name" class="policy-row">
|
||||||
<strong>{{ item.name }}</strong>
|
<strong class="policy-title-cell">{{ item.name }}</strong>
|
||||||
<span>{{ item.summary }}</span>
|
<span class="policy-summary-cell">{{ item.summary }}</span>
|
||||||
<span>{{ item.date }}</span>
|
<span class="policy-date-cell">{{ item.date }}</span>
|
||||||
<span>
|
|
||||||
<b class="policy-status" :class="item.tone">{{ item.status }}</b>
|
|
||||||
</span>
|
|
||||||
<button type="button" class="row-link" :aria-label="`查看 ${item.name}`">
|
|
||||||
<i class="mdi mdi-chevron-right"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -119,6 +118,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import PanelHead from '../shared/PanelHead.vue'
|
import PanelHead from '../shared/PanelHead.vue'
|
||||||
|
import robotAssistant from '../../assets/robot-assistant.png'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
showHeader: { type: Boolean, default: true }
|
showHeader: { type: Boolean, default: true }
|
||||||
@@ -131,27 +131,32 @@ const assistantSkills = ['识别报销类别', '检查缺少材料', '生成报
|
|||||||
const todoItems = [
|
const todoItems = [
|
||||||
{
|
{
|
||||||
title: '业务招待报销建议补参与人员',
|
title: '业务招待报销建议补参与人员',
|
||||||
suggestion: 'AI 建议:补充客户单位、客户人数、我方陪同人员',
|
tipLabel: 'AI 建议',
|
||||||
|
suggestion: '补充客户单位、客户人数、我方陪同人员',
|
||||||
action: '去补充',
|
action: '去补充',
|
||||||
icon: 'mdi mdi-account-group-outline',
|
icon: 'mdi mdi-account-group-outline',
|
||||||
color: '#10b981'
|
color: '#10b981'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '差旅报销单待提交',
|
title: '差旅报销单待提交',
|
||||||
suggestion: 'AI 建议:补齐出发交通,可直接生成报销单',
|
tipLabel: 'AI 建议',
|
||||||
|
suggestion: '补齐出发交通,可直接生成报销单',
|
||||||
action: '继续填写',
|
action: '继续填写',
|
||||||
icon: 'mdi mdi-briefcase-outline',
|
icon: 'mdi mdi-briefcase-outline',
|
||||||
color: '#16a34a'
|
color: '#16a34a'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '有 5 张票据未关联报销单',
|
title: '有 5 张票据未关联报销单',
|
||||||
suggestion: 'AI 建议:其中 3 张疑似交通费,可合并生成交通报销',
|
tipLabel: 'AI 建议',
|
||||||
|
suggestion: '其中 3 张疑似交通费,可合并生成交通报销',
|
||||||
action: '去整理',
|
action: '去整理',
|
||||||
icon: 'mdi mdi-receipt-text-outline',
|
icon: 'mdi mdi-receipt-text-outline',
|
||||||
color: '#3b82f6'
|
color: '#3b82f6'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const todoAlertCount = todoItems.length
|
||||||
|
|
||||||
const progressItems = [
|
const progressItems = [
|
||||||
{
|
{
|
||||||
id: 'travel',
|
id: 'travel',
|
||||||
@@ -185,34 +190,28 @@ const progressItems = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const progressAlertCount = progressItems.filter((item) => item.status !== '已到账').length
|
||||||
|
|
||||||
const policyItems = [
|
const policyItems = [
|
||||||
{
|
{
|
||||||
name: '差旅报销管理办法(2026版)',
|
name: '差旅报销管理办法(2026版)',
|
||||||
summary: '更新住宿标准与交通等级规则',
|
summary: '更新住宿标准与交通等级规则',
|
||||||
date: '2026-05-04',
|
date: '2026-05-04'
|
||||||
status: '已生效',
|
|
||||||
tone: 'success'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '业务招待费用报销规范',
|
name: '业务招待费用报销规范',
|
||||||
summary: '明确参与人员与事由填写要求',
|
summary: '明确参与人员与事由填写要求',
|
||||||
date: '2026-05-02',
|
date: '2026-05-02'
|
||||||
status: '更新',
|
|
||||||
tone: 'warning'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '交通费用报销细则',
|
name: '交通费用报销细则',
|
||||||
summary: '补充网约车与停车费报销说明',
|
summary: '补充网约车与停车费报销说明',
|
||||||
date: '2026-04-28',
|
date: '2026-04-28'
|
||||||
status: '已生效',
|
|
||||||
tone: 'success'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '票据与附件提交规范通知',
|
name: '票据与附件提交规范通知',
|
||||||
summary: '统一附件命名与上传要求',
|
summary: '统一附件命名与上传要求',
|
||||||
date: '2026-04-25',
|
date: '2026-04-25'
|
||||||
status: '通知',
|
|
||||||
tone: 'info'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
@@ -306,6 +305,13 @@ const policyItems = [
|
|||||||
font-size: 68px;
|
font-size: 68px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assistant-image {
|
||||||
|
width: 104px;
|
||||||
|
height: 104px;
|
||||||
|
object-fit: contain;
|
||||||
|
filter: drop-shadow(0 12px 20px rgba(15, 23, 42, 0.12));
|
||||||
|
}
|
||||||
|
|
||||||
.assistant-copy {
|
.assistant-copy {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@@ -454,18 +460,27 @@ const policyItems = [
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.count-chip {
|
.title-with-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-badge {
|
||||||
|
min-width: 22px;
|
||||||
|
height: 22px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 46px;
|
padding: 0 7px;
|
||||||
height: 28px;
|
|
||||||
padding: 0 10px;
|
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #ecfdf5;
|
background: #ef4444;
|
||||||
color: #0f9f78;
|
color: #fff;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
line-height: 1;
|
||||||
|
box-shadow: 0 6px 14px rgba(239, 68, 68, 0.22);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-action {
|
.link-action {
|
||||||
@@ -527,6 +542,30 @@ const policyItems = [
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.todo-advice {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-advice-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 22px;
|
||||||
|
padding: 0 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #ecfdf5;
|
||||||
|
color: #059669;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-advice-text {
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
.row-action {
|
.row-action {
|
||||||
height: 38px;
|
height: 38px;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
@@ -538,27 +577,37 @@ const policyItems = [
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-copy .progress-main {
|
.progress-row {
|
||||||
display: flex;
|
grid-template-columns: 48px minmax(0, 1fr) minmax(84px, auto) minmax(104px, auto);
|
||||||
align-items: center;
|
gap: 14px 16px;
|
||||||
justify-content: space-between;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-copy .amount {
|
.progress-copy strong {
|
||||||
font-size: 17px;
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-amount {
|
||||||
|
color: #0f172a;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: right;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-status {
|
.progress-status {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-height: 32px;
|
min-width: 104px;
|
||||||
padding: 6px 12px;
|
min-height: 34px;
|
||||||
|
padding: 6px 14px;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
justify-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-status.success,
|
.progress-status.success,
|
||||||
@@ -586,7 +635,7 @@ const policyItems = [
|
|||||||
|
|
||||||
.policy-row {
|
.policy-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2.1fr 2.2fr 1fr auto 40px;
|
grid-template-columns: 2.2fr 2.4fr 1fr;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 56px;
|
min-height: 56px;
|
||||||
@@ -622,30 +671,15 @@ const policyItems = [
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.policy-status {
|
.policy-title-cell,
|
||||||
display: inline-flex;
|
.policy-summary-cell {
|
||||||
align-items: center;
|
justify-self: stretch;
|
||||||
justify-content: center;
|
text-align: left;
|
||||||
min-width: 66px;
|
|
||||||
min-height: 28px;
|
|
||||||
padding: 0 10px;
|
|
||||||
border-radius: 999px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.policy-status.warning {
|
.policy-date-cell {
|
||||||
background: #fff7e8;
|
justify-self: center;
|
||||||
color: #f59e0b;
|
text-align: center;
|
||||||
}
|
|
||||||
|
|
||||||
.row-link {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: #94a3b8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1320px) {
|
@media (max-width: 1320px) {
|
||||||
@@ -654,7 +688,7 @@ const policyItems = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
.policy-row {
|
.policy-row {
|
||||||
grid-template-columns: 1.7fr 1.7fr 1fr auto 32px;
|
grid-template-columns: 1.8fr 1.8fr 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,6 +735,12 @@ const policyItems = [
|
|||||||
grid-template-columns: 48px minmax(0, 1fr);
|
grid-template-columns: 48px minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-amount {
|
||||||
|
grid-column: 2;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.row-action,
|
.row-action,
|
||||||
.progress-status {
|
.progress-status {
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
@@ -727,9 +767,5 @@ const policyItems = [
|
|||||||
.policy-row span {
|
.policy-row span {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.policy-row > :last-child {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const sidebarMeta = {
|
|||||||
approval: { label: '审批中心', badge: '12' },
|
approval: { label: '审批中心', badge: '12' },
|
||||||
chat: { label: 'AI助手' },
|
chat: { label: 'AI助手' },
|
||||||
policies: { label: '知识管理' },
|
policies: { label: '知识管理' },
|
||||||
audit: { label: '审计追踪' }
|
audit: { label: '技能中心' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const decoratedNavItems = computed(() =>
|
const decoratedNavItems = computed(() =>
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ export const navItems = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'audit',
|
id: 'audit',
|
||||||
label: '审计追踪',
|
label: '技能中心',
|
||||||
navHint: '关键动作与日志',
|
navHint: 'Skill 设计与版本配置',
|
||||||
icon: icons.audit,
|
icon: icons.skill,
|
||||||
title: '审计追踪',
|
title: '技能中心',
|
||||||
desc: '查看关键审批动作、AI 建议和制度命中记录'
|
desc: '统一管理技能的触发规则、提示词结构、输出约束与上线版本'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const icons = {
|
|||||||
list: iconPath('<path d="M8 6h13"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M3 6h.01"/><path d="M3 12h.01"/><path d="M3 18h.01"/>'),
|
list: iconPath('<path d="M8 6h13"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M3 6h.01"/><path d="M3 12h.01"/><path d="M3 18h.01"/>'),
|
||||||
approval: iconPath('<path d="M9 11l2 2 4-5"/><path d="M20 12v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h8"/><path d="M17 3h4v4"/>'),
|
approval: iconPath('<path d="M9 11l2 2 4-5"/><path d="M20 12v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h8"/><path d="M17 3h4v4"/>'),
|
||||||
file: iconPath('<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M8 13h8"/><path d="M8 17h5"/>'),
|
file: iconPath('<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M8 13h8"/><path d="M8 17h5"/>'),
|
||||||
|
skill: iconPath('<path d="M12 3 9.5 8.5 3 11l6.5 2.5L12 19l2.5-5.5L21 11l-6.5-2.5z"/><path d="M19 19l.9 2 .9-2 2-.9-2-.9-.9-2-.9 2-2 .9z"/><path d="M5 5l.6 1.4L7 7l-1.4.6L5 9l-.6-1.4L3 7l1.4-.6z"/>'),
|
||||||
audit: iconPath('<path d="M12 8v4l3 3"/><path d="M3.05 11a9 9 0 1 1 .5 4"/><path d="M3 4v7h7"/>'),
|
audit: iconPath('<path d="M12 8v4l3 3"/><path d="M3.05 11a9 9 0 1 1 .5 4"/><path d="M3 4v7h7"/>'),
|
||||||
search: iconPath('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),
|
search: iconPath('<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>'),
|
||||||
check: iconPath('<path d="M20 6 9 17l-5-5"/>'),
|
check: iconPath('<path d="M20 6 9 17l-5-5"/>'),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1893
src/views/TravelRequestDetailView.vue
Normal file
1893
src/views/TravelRequestDetailView.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user