feat(frontend): 公司设置/二次分配/审批三页接入,参数页编码中文化
- 公司信息页(设置 order7):名称编辑 + logo 上传(png/jpg ≤2MB 前端先拦)+ 签名元素「登录页实景预览」(缩比登录卡,品牌名/logo 即时反映,所见即所得) - 审批管理页(order8):列表筛选(关键词/状态/类型)+ 签名元素 「竖排节点时间线」(财务复核→领导审核,人工/自动/驳回色区分)+ 在途单通过/驳回动作(驳回必填意见,经 useConfirmAction 确认流) - 路由扩展 allowedRoles 元数据:菜单按任一列入角色可见 + 守卫双 过滤(admin 须显式列入集合,不天然放行);审批页对 admin/ finance/leader 可见(营销后勤待权限清单 #6) - 业务表单二次分配区:参与人下拉(离职禁用)+比例输入+实时合计条 (合计≠100% 提示余额归属待业务确认,满额高亮);编辑全量替换、 空行自动忽略;校验(人员非重/比例两位小数)与后端 NUMERIC(5,2) 同口径 - 登录页接 /system/settings/public:品牌名与页脚动态,logo 展示, 失败静默回退默认(登录页必须可用) - 参数页中文化:维度角色名映射(营销员/营销经理/信息员)、枚举值 中文(当月全额/余额、含/扣/不计基本工资、开/关)、预览「所用参数」 由编码直出改中文名(编码括注) - 验证:pnpm type-check 零错误;pnpm build 通过 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
74f1ef1cf9
commit
927592b472
@ -103,7 +103,8 @@ onMounted(() => {
|
|||||||
<div class="login-wrap">
|
<div class="login-wrap">
|
||||||
<div class="login-card">
|
<div class="login-card">
|
||||||
<div class="card-brand">
|
<div class="card-brand">
|
||||||
<div class="card-brand__name">衍水集团</div>
|
<img v-if="brandLogo" :src="brandLogo" alt="" class="card-brand__logo" />
|
||||||
|
<div class="card-brand__name">{{ brandName }}</div>
|
||||||
<p class="card-brand__slogan">把每一笔回款,算成一份踏实。</p>
|
<p class="card-brand__slogan">把每一笔回款,算成一份踏实。</p>
|
||||||
<span class="waterline"></span>
|
<span class="waterline"></span>
|
||||||
</div>
|
</div>
|
||||||
@ -169,7 +170,7 @@ onMounted(() => {
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="login-foot">© 衍水集团 · 内部系统</p>
|
<p class="login-foot">© {{ brandName }} · 内部系统</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -270,6 +271,14 @@ onMounted(() => {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-brand__logo {
|
||||||
|
display: block;
|
||||||
|
max-width: 56px;
|
||||||
|
max-height: 36px;
|
||||||
|
margin: 0 auto 10px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
.card-brand__name {
|
.card-brand__name {
|
||||||
font-family: var(--ys-font-brand);
|
font-family: var(--ys-font-brand);
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
|||||||
@ -101,14 +101,19 @@ async function submitAction(): Promise<void> {
|
|||||||
}
|
}
|
||||||
actionSubmitting.value = true
|
actionSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
const run = () =>
|
const ok = await confirmAndRun({
|
||||||
actApproval(actingId.value as number, {
|
confirmText:
|
||||||
action: actionForm.action,
|
actionForm.action === 1
|
||||||
opinion: actionForm.opinion.trim() || null,
|
? `确认通过审批单 ${actingId.value}?通过后进入下一节点。`
|
||||||
})
|
: `确认驳回审批单 ${actingId.value}?驳回后该单终止。`,
|
||||||
await confirmAndRun(run, {
|
run: () =>
|
||||||
successMessage: actionForm.action === 1 ? '已通过' : '已驳回',
|
actApproval(actingId.value as number, {
|
||||||
|
action: actionForm.action,
|
||||||
|
opinion: actionForm.opinion.trim() || null,
|
||||||
|
}),
|
||||||
|
successText: actionForm.action === 1 ? '已通过' : '已驳回',
|
||||||
})
|
})
|
||||||
|
if (!ok) return
|
||||||
// 动作后刷新抽屉与列表(状态可能已流转或终态)
|
// 动作后刷新抽屉与列表(状态可能已流转或终态)
|
||||||
detail.value = await getApproval(actingId.value)
|
detail.value = await getApproval(actingId.value)
|
||||||
actingId.value = null
|
actingId.value = null
|
||||||
|
|||||||
@ -37,6 +37,10 @@ async function loadCatalog(): Promise<void> {
|
|||||||
catalogLoading.value = true
|
catalogLoading.value = true
|
||||||
try {
|
try {
|
||||||
catalog.value = await paramsApi.getCatalog()
|
catalog.value = await paramsApi.getCatalog()
|
||||||
|
// 预览「所用参数」按编码取中文名;目录加载后填充映射
|
||||||
|
for (const item of catalog.value) {
|
||||||
|
PARAM_NAME_BY_CODE[item.param_code] = item.param_name
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handledError(error)
|
handledError(error)
|
||||||
} finally {
|
} finally {
|
||||||
@ -53,17 +57,42 @@ const groupedCatalog = computed(() => {
|
|||||||
return [...groups.entries()].map(([name, items]) => ({ name, items }))
|
return [...groups.entries()].map(([name, items]) => ({ name, items }))
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 维度值 → 展示名(NONE 维度为空串) */
|
/** 维度值 → 展示名(NONE 维度为空串;角色维度给出中文岗位名) */
|
||||||
const DIMENSION_LABELS: Record<string, string> = {
|
const DIMENSION_LABELS: Record<string, string> = {
|
||||||
'': '默认',
|
'': '默认',
|
||||||
municipal_water: '市政水利',
|
municipal_water: '市政水利',
|
||||||
rail_transit: '轨道交通',
|
rail_transit: '轨道交通',
|
||||||
|
salesperson: '营销员',
|
||||||
|
sales_manager: '营销经理',
|
||||||
|
info_officer: '信息员',
|
||||||
}
|
}
|
||||||
|
|
||||||
function dimensionLabel(dimension: string): string {
|
function dimensionLabel(dimension: string): string {
|
||||||
return DIMENSION_LABELS[dimension] ?? dimension
|
return DIMENSION_LABELS[dimension] ?? dimension
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 参数名 → 中文(预览「所用参数」列表用;编辑/历史/对比抽屉另有 param_name 直出) */
|
||||||
|
const PARAM_NAME_BY_CODE: Record<string, string> = {}
|
||||||
|
function paramNameByCode(code: string): string {
|
||||||
|
return PARAM_NAME_BY_CODE[code] ?? code
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 枚举值 → 中文(FULL/BALANCE、INCLUDE/DEDUCT/EXCLUDE、0/1 开关) */
|
||||||
|
const ENUM_VALUE_LABELS: Record<string, string> = {
|
||||||
|
FULL: '当月全额',
|
||||||
|
BALANCE: '余额',
|
||||||
|
INCLUDE: '含基本工资',
|
||||||
|
DEDUCT: '扣除基本工资',
|
||||||
|
EXCLUDE: '不计基本工资',
|
||||||
|
'0': '关',
|
||||||
|
'1': '开',
|
||||||
|
}
|
||||||
|
|
||||||
|
function valueLabel(value: string | null | undefined): string {
|
||||||
|
if (value === null || value === undefined) return ''
|
||||||
|
return ENUM_VALUE_LABELS[value] ?? value
|
||||||
|
}
|
||||||
|
|
||||||
/** 带单位的值展示 */
|
/** 带单位的值展示 */
|
||||||
function formatValue(item: ParamCatalogItem, value: string): string {
|
function formatValue(item: ParamCatalogItem, value: string): string {
|
||||||
return item.unit ? `${value} ${item.unit}` : value
|
return item.unit ? `${value} ${item.unit}` : value
|
||||||
@ -763,7 +792,7 @@ onMounted(() => {
|
|||||||
<div class="pr-used">
|
<div class="pr-used">
|
||||||
<div class="drawer-title">所用参数(按回款到账日取值)</div>
|
<div class="drawer-title">所用参数(按回款到账日取值)</div>
|
||||||
<div v-for="u in previewResult.params_used" :key="u.param_code" class="pr-used-row">
|
<div v-for="u in previewResult.params_used" :key="u.param_code" class="pr-used-row">
|
||||||
{{ u.param_code }} = {{ u.value_text }}
|
{{ paramNameByCode(u.param_code) }}({{ u.param_code }})= {{ valueLabel(u.value_text) || u.value_text }}
|
||||||
<span v-if="u.effective_date" class="eff">({{ u.effective_date }} 起)</span>
|
<span v-if="u.effective_date" class="eff">({{ u.effective_date }} 起)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
import { computed, reactive, ref } from 'vue'
|
||||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||||
import type { UploadRawFile } from 'element-plus'
|
import type { UploadRawFile } from 'element-plus'
|
||||||
|
|
||||||
@ -12,6 +12,8 @@ import { handledError } from '@/utils/error'
|
|||||||
* 签名元素是右侧「登录页实景预览」:品牌名与 logo 改动即时反映在一张
|
* 签名元素是右侧「登录页实景预览」:品牌名与 logo 改动即时反映在一张
|
||||||
* 缩比登录卡上 —— 所见即所得,避免「保存后去登录页核对」的往返。
|
* 缩比登录卡上 —— 所见即所得,避免「保存后去登录页核对」的往返。
|
||||||
* logo 校验(png/jpg ≤2MB)与后端三重校验同口径,前端先拦一道。
|
* logo 校验(png/jpg ≤2MB)与后端三重校验同口径,前端先拦一道。
|
||||||
|
*
|
||||||
|
* 进入页面即加载当前设置(设置页即所见即所得,无需手动刷新)。
|
||||||
*/
|
*/
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
@ -40,6 +42,8 @@ async function loadSettings(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadSettings()
|
||||||
|
|
||||||
async function handleSubmit(): Promise<void> {
|
async function handleSubmit(): Promise<void> {
|
||||||
const valid = await formRef.value?.validate().catch(() => false)
|
const valid = await formRef.value?.validate().catch(() => false)
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user