feat: 增强员工管理与报销单全流程功能

- 新增员工Excel导入服务(employee_spreadsheet)及导入/导出API端点
- 员工服务增加批量创建、邮箱唯一校验、组织架构关联等能力
- 报销单提交补充身份回填、部门信息透传及预审结果展示优化
- 认证流程增加部门信息(departmentName)并在schema中同步扩展
- 用户Agent服务增加部门关联与报销单回填逻辑
- 前端员工管理页面全面重构,新增导入导出、搜索过滤、分页等功能
- 前端审批中心、审计、差旅报销等视图交互与样式优化
- 新增TableLoadingState共享组件及员工导入测试用例
This commit is contained in:
caoxiaozhu
2026-05-20 14:21:56 +08:00
parent 57957d11a0
commit d7e98a58b9
46 changed files with 4022 additions and 305 deletions

View File

@@ -511,18 +511,23 @@
<div v-if="composerDateMode === 'single'" class="composer-date-fields">
<label class="composer-date-field">
<span>日期</span>
<input v-model="composerSingleDate" type="date" />
<input v-model="composerSingleDate" type="date" @change="handleComposerDateInputChange" />
</label>
</div>
<div v-else class="composer-date-fields composer-date-fields-range">
<label class="composer-date-field">
<span>开始</span>
<input v-model="composerRangeStartDate" type="date" />
<input v-model="composerRangeStartDate" type="date" @change="handleComposerDateInputChange" />
</label>
<span class="composer-date-range-sep"></span>
<label class="composer-date-field">
<span>结束</span>
<input v-model="composerRangeEndDate" type="date" :min="composerRangeStartDate" />
<input
v-model="composerRangeEndDate"
type="date"
:min="composerRangeStartDate"
@change="handleComposerDateInputChange"
/>
</label>
</div>
<p v-if="composerDateMode === 'range' && !composerCanApplyDateSelection" class="composer-date-hint">
@@ -1078,9 +1083,28 @@
</span>
</div>
<p class="review-side-risk-summary">{{ reviewRiskSummary }}</p>
<ul v-if="reviewRiskItems.length" class="review-side-risk-list">
<li v-for="item in reviewRiskItems" :key="item">{{ item }}</li>
</ul>
<div v-if="reviewRiskItems.length" class="review-side-risk-list">
<button
v-for="item in reviewRiskItems"
:key="item.key"
type="button"
class="review-side-risk-item"
:class="item.level"
@click="openReviewRiskDetail(item)"
>
<span class="review-side-risk-icon">
<i :class="item.icon"></i>
</span>
<span class="review-side-risk-copy">
<strong>{{ item.title }}</strong>
<p>{{ item.summary }}</p>
</span>
<span class="review-side-risk-meta">
{{ item.levelLabel }}
<i class="mdi mdi-chevron-right"></i>
</span>
</button>
</div>
<div v-else-if="reviewRiskEmpty" class="review-side-empty">
<span class="review-side-empty-icon">
<i class="mdi mdi-shield-check-outline"></i>
@@ -1088,16 +1112,6 @@
<strong>暂无风险评分</strong>
<p>当前版本还没有返回结构化风险评分结果这里先不展示虚拟分数</p>
</div>
<button
v-if="reviewRiskActionAvailable"
type="button"
class="review-side-link"
:disabled="submitting || reviewActionBusy"
@click="explainCurrentReviewRisk"
>
查看全部风险项
<i class="mdi mdi-chevron-right"></i>
</button>
</section>
</template>
@@ -1192,6 +1206,41 @@
@confirm="confirmCancelReview"
/>
<Transition name="assistant-modal">
<div v-if="reviewRiskDetailDialog.open" class="assistant-overlay review-overlay">
<section class="review-risk-detail-modal">
<header class="review-risk-detail-head">
<div>
<span class="assistant-badge warning">{{ reviewRiskDetailDialog.item?.sourceLabel || 'AI预审' }}</span>
<h3>{{ reviewRiskDetailDialog.item?.title || '风险提示' }}</h3>
</div>
<button class="close-btn" type="button" aria-label="关闭风险说明" @click="closeReviewRiskDetail">
<i class="mdi mdi-close"></i>
</button>
</header>
<div class="review-risk-detail-body">
<div class="review-risk-detail-level" :class="reviewRiskDetailDialog.item?.level">
<i :class="reviewRiskDetailDialog.item?.icon || 'mdi mdi-information-outline'"></i>
<span>{{ reviewRiskDetailDialog.item?.levelLabel || '提示' }}</span>
</div>
<article class="review-risk-detail-section">
<strong>提示情况</strong>
<p>{{ reviewRiskDetailDialog.item?.summary }}</p>
</article>
<article class="review-risk-detail-section">
<strong>详细解释</strong>
<p>{{ reviewRiskDetailDialog.item?.detail }}</p>
</article>
<article class="review-risk-detail-section">
<strong>处理建议</strong>
<p>{{ reviewRiskDetailDialog.item?.suggestion }}</p>
</article>
</div>
</section>
</div>
</Transition>
<Transition name="assistant-modal">
<div v-if="uploadDecisionDialogOpen" class="assistant-overlay review-overlay">
<section class="review-confirm-modal review-upload-decision-modal">