Merge remote-tracking branch 'websoft/master'

This commit is contained in:
2026-08-27 23:52:21 +08:00
10 changed files with 195 additions and 157 deletions
+8 -54
View File
@@ -1,58 +1,12 @@
# 2026-08-27 工作日志 # 2026-08-27 工作日志
## 全站底部操作栏「返回」按钮统一改为「取消」 ## project-apply 表单 UI 调整(新增 / 重大项目补录)
- 起因:用户访问 `/vehicle/customer-archive/form` 独立表单页,指出底部「返回」按钮应全站统一为「取消」。 文件:`src/views/business/project-apply.vue`
- 改动文件(模板/逻辑中的「返回」→「取消」):
- `src/views/vehicle/customer-archive.vue`:主表单页 footer 逻辑 `readonly ? '关闭' : isArchivePage ? '返回' : '取消'``readonly ? '关闭' : '取消'`4 处子弹窗(contact/receipt/invoice/score`>返回</el-button>``>取消</el-button>`replace_all)。
- `src/views/payment/invoice-receipt-form.vue``payment-application-form.vue``payment/payment-application-form.vue``goBack` 返回按钮 →「取消」。
- `src/views/business/components/master-order-editor.vue``master-order-dispatch.vue``master-order-detail.vue``$emit('back')` 返回按钮 →「取消」。
- `src/views/business/components/business-crud-page.vue`:运输计划导入弹窗关闭按钮 →「取消」。
- `src/views/system/user.vue`:用户弹窗关闭按钮 →「取消」。
- `src/views/business/project-apply.vue`:独立表单页(isProjectFormPage`closeProjectForm` 返回按钮 ×2 →「取消」。
- 未改动:`src/lang/zh.js` 登录 i18n 段 `back: '返回'`(无 `$t('back')` 引用,属登录流程返回,非业务 footer 操作栏)。
- 规范固化:更新 MEMORY.md「弹窗 / 独立表单页底栏按钮统一规则」,明确全站底部操作栏「返回」统一为「取消」,仅只读查看 / 纯关闭场景保留「关闭」。
## 发货模板独立表单页(shipping-template/formfooter 缺「取消」+ 去图标 按截图需求修改项目管理表单(新增 + 重大项目补录同步):
- 起因:用户访问 `/business/shipping-template/form?mode=add`,指出底部按钮缺「取消」且不需要图标(统一只要文字) 1. 项目编号放开编辑(去掉 `disabled`),placeholder 改为"请输入项目编号,不填自动生成";编辑模式仍禁用
- 该页极薄,仅 `<business-crud-page standalone-form-page>`footer 由 `business-crud-page.vue``PageAvueForm` 渲染 2. 项目简称取消必填校验(仅保留 maxlength 20
- 改动(`src/views/business/components/business-crud-page.vue` 3. 业务部门、项目由来说明单独占一行(新增 class `project-apply-form__item--full` + 样式 `grid-column: 1 / -1`
- `#menu-form-before` 次要按钮 `关闭``取消`(条件 `isStandaloneFormPage && !showTransportPlanCreateActions`),影响 `/waybill-manage/form``/transport-plan/form``/shipping-template/form` 三处独立表单页 4. 业务部门下拉过滤"外部组织":原仅 `['add','edit']` 过滤,已补上 `majorSupplement`,重大项目补录不再显示外部组织
- `#menu-form` 的运输计划创建模式次要按钮 `关闭``取消`
- 新增样式 `:global(.business-crud-form-page-dialog .avue-form__menu .el-icon){display:none}`Avue 的 `avue-form` 提交/清空按钮内置图标(`submitIcon:'el-icon-check'``emptyIcon:'el-icon-delete'`),且 Avue 源码用 `||` 兜底无法通过 option 去除,故用 CSS 在独立表单页容器内统一隐藏图标,仅保留文字,不影响其它弹窗。
- 规范固化:MEMORY.md「弹窗 / 独立表单页底栏按钮统一规则」补充「独立表单页 Avue 表单 footer 去图标(统一纯文字)」说明。
## 底部操作栏按钮间距统一去 gap 待确认:后端 submit/saveDraft 在 `projectCode` 为空时是否自动生成编号(用户让后端同事补)。
- 起因:用户指出这些底部按钮间距不一致,要求统一,并把用了 `gap` 的全部去掉。
- 方案:所有底部操作栏(footer / `__actions` / `page-actions`**移除 `gap`**,间距统一回落到 Element Plus 全局默认的相邻按钮 `.el-button+.el-button{margin-left:12px}`(恒为 12px),不再散落 `gap:8/12/16px`
- 全局对齐:`.el-dialog__footer .el-button + .el-button``margin-left:8px` 改为 `12px``src/styles/element-ui.scss`),使弹窗 footer 也与之一致。
- 已去 gap 的 footer 容器:`vehicle/customer-archive.vue`(`.archive-form__footer`)、`business/components/master-order-editor.vue`(`footer`)、`business/components/master-order-dispatch.vue`(`.segment-actions`/`.pending-actions`)、`business/project-apply.vue`(`.project-apply-dialog__footer`)、`business/components/business-crud-page.vue`(`.business-crud-form-page-dialog .avue-form__menu`)、payment 6 个表单页(`*__actions`)、`settlement/components/pre-settlement-editor.vue`(`&__page-actions`)、`settlement/components/formal-settlement-editor.vue`(`.formal-editor__page-actions`)、`settlement/receivable-payable-detail.vue`(`.settlement-detail-page__actions`)。
- 风控:确认 Avue 的 `.avue-form__menu`/`.avue-dialog__footer` 自身不带按钮间距,去掉 gap 后由 EP 默认 12px margin 接管(不会贴死)。
- 范围说明:本次聚焦近几轮在统一的模块(vehicle/payment/business/settlement)。若要把 loading-manage、contract-manage、transit 等其它模块的底部栏也纳入,需再处理。
## 客商档案搜索区「所属组织」从扁平下拉改为树形下拉
- 起因:用户截图 `/vehicle/customer-archive` 搜索区,指出「所属组织」是扁平下拉,要求统一按新增/编辑表单(多选 `el-tree-select`)实现。
- 原 column 配置:`prop: 'deptName'` + `search: true` + `searchType: 'select'` + `dicData: [{label:'全部',value:''}, ...flattenDept]`initDeptTree() 异步把 dicData 写回 column(数据已加载,只是渲染风格不一致)。
- 改动:
- column 移除 `searchType: 'select'``searchValue: ''``dicData`,仅保留 `search: true, searchOrder: 1`
- `initDeptTree()` 中改写 `deptColumn.renderSearch = scope => this.renderDeptSearch(scope)`
- 新增 `methods.renderDeptSearch(scope)`:通过 `vue``h` 函数返回一个 `el-tree-select` vnode(多选 + check-strictly + 树形 + 折叠 tag + 全宽),onUpdate 时把 ID 数组按 `deptOptions` 查 rawLabel,逗号拼接写入 `scope.row.deptName`(即 searchForm.deptName),保持后端接口字段不变。
- `searchChange/searchReset` 链路无需改:`onLoad` 已通过 `query` 透传 deptName 到后端。
- `src/styles/element-ui.scss` 新增 `.avue-crud__search .el-form-item__content > .el-tree-select { width:100%; max-width:100%; }`:搜索区树形下拉全宽兜底,不影响新增/编辑表单(用 `el-col :span=6` 栅格自然分开)。
- 方案说明:Avue-crud 搜索 form-temp 内部 render 函数支持 column.renderSearch 自定义渲染(`header-search2.mjs` 行 93 `render: ele.renderSearch`),不需要重写整个搜索区;自定义 slot `<template #search-deptName>` 在 el-input 等自闭合组件上无法落地(slot 名不会被 el-input 识别),所以走 renderSearch。
- 选择项:用户确认「仅替换所属组织一格」「多选」「传 deptName」三项。
- 排查「出不来了」反馈:主人实测搜索区只有 label,控件区域空白。原因 `h('el-tree-select', {...})` 传字符串时 Vue 3 `_createVNode` 直接把 type 当 ELEMENTshapeFlag=1)处理,**不会调用 resolveComponent**,结果浏览器渲染出未知标签 `<el-tree-select>`,内容为空。
- 修复:从 `element-plus` import `ElTreeSelect` 组件对象,`h(ElTreeSelect, {...})` 走组件 vnode 路径;同时把 `modelValue` 默认值改为 `[]`(多选模式数组要求,避免 el-tree-select 警告)。
- 教训:Avue `column.render`/`renderSearch` 等接受 vnode 的字段,传字符串组件名时 Vue 不会 resolve,必须直接 import 组件对象或在 setup 内 `resolveComponent()`
- 排查「选中不了」反馈:控件显示出来了,但点击树节点无法选中/再选。根因 `onUpdate:modelValue` 里把 `scope.row.deptName` 写成了名字**字符串**,而该字段正是 el-tree-select 的 `modelValue`(多选模式必须是**ID 数组**),第一次选中后 modelValue 变字符串,el-tree-select 内部状态错乱,后续点击无法更新。
- 修复:renderDeptSearch 的 `onUpdate:modelValue` 只把 `scope.row.deptName` 写成 ID 数组(保留数组形态);在 `searchChange(params, done)` 里把 Avue 拷贝出来的 `params.deptName` 数组(注意:`filterParams``deepClone`params 与 scope.row 是不同引用,改它不破坏搜索框显示)按 `deptOptions` 查 rawLabel 再 `join(',')` 转成名字字符串写入 `query`,后端字段 deptName 不变。重置由 Avue `resetForm` 清空 scope.row.deptName 为 `''`renderDeptSearch 读到非数组回退 `[]` 显示空,无需额外处理。
## 船舶表单「安放龙骨日期/建造完工日期」label 收窄并换行
- 起因:用户截图 `transportCapacity/ship` 新增船舶弹窗,指出该字段 label 宽达 185px,要求最大 88px 并允许换行。
- 改动:`src/views/transportCapacity/ship.vue` 第 169 行,给该 `el-form-item` 增加 `label-width="88px"` 覆盖全局 `label-width="100"`;全局 `.ship-form :deep(.el-form-item__label)` 已设置 `white-space: normal; line-height: 20px`,换行已支持。
## 船舶证书信息两块表单改 4 列
- 起因:用户截图 `transportCapacity/ship` 船舶证书信息,指出「船舶所有权证书」「内河船舶安全与环保证书」两块想改成 4 列。
- 改动:`src/views/transportCapacity/ship.vue`
- 「船舶所有权证书」5 个字段:第一行 `登记号码/初次登记号码/船舶所有人/取得所有权日期` 4 列,第二行 `船舶识别号` 1 列(所有 `el-col :span="8"``:span="6"`)。
- 「内河船舶安全与环保证书」4 个字段:合并为一行 4 列(`总吨/净吨/船检登记号/船舶类型`),`el-col :span="8"``:span="6"`
- 未改动:船舶国籍证书、最低安全配员证书(日期范围,保持 `span=16` 整行)、光船租赁登记证明书、船舶营业运输证书(用户未要求)。
+7 -2
View File
@@ -4,6 +4,11 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
patchedDependencies:
'@smallwei/avue':
hash: 5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db
path: patches/@smallwei__avue.patch
importers: importers:
.: .:
@@ -28,7 +33,7 @@ importers:
version: 1.7.0 version: 1.7.0
'@smallwei/avue': '@smallwei/avue':
specifier: ~3.9.2 specifier: ~3.9.2
version: 3.9.2(@element-plus/icons-vue@2.3.2(vue@3.5.34))(element-plus@2.14.2(vue@3.5.34))(vue@3.5.34) version: 3.9.2(patch_hash=5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db)(@element-plus/icons-vue@2.3.2(vue@3.5.34))(element-plus@2.14.2(vue@3.5.34))(vue@3.5.34)
animate.css: animate.css:
specifier: ^4.1.1 specifier: ^4.1.1
version: 4.1.1 version: 4.1.1
@@ -2648,7 +2653,7 @@ snapshots:
countup.js: 2.10.0 countup.js: 2.10.0
signature_pad: 5.1.3 signature_pad: 5.1.3
'@smallwei/avue@3.9.2(@element-plus/icons-vue@2.3.2(vue@3.5.34))(element-plus@2.14.2(vue@3.5.34))(vue@3.5.34)': '@smallwei/avue@3.9.2(patch_hash=5ba15ad41b2c301250bf24adf39da2ed526b8375143da2c5a495361b29e862db)(@element-plus/icons-vue@2.3.2(vue@3.5.34))(element-plus@2.14.2(vue@3.5.34))(vue@3.5.34)':
dependencies: dependencies:
'@element-plus/icons-vue': 2.3.2(vue@3.5.34) '@element-plus/icons-vue': 2.3.2(vue@3.5.34)
axios: 0.21.4 axios: 0.21.4
+17 -29
View File
@@ -21,18 +21,6 @@ const amountRules = label => [
nonNegativeRule(label), nonNegativeRule(label),
]; ];
const userDicFormatter = res => {
const list = Array.isArray(res)
? res
: Array.isArray(res.data)
? res.data
: res.data?.records || [];
return list.map(user => ({
...user,
realName: user.realName || user.name || user.account,
}));
};
const formatUserRealName = (row, role) => const formatUserRealName = (row, role) =>
row[`${role}RealName`] || row[`${role}RealName`] ||
row[`${role}UserRealName`] || row[`${role}UserRealName`] ||
@@ -103,11 +91,11 @@ export const config = {
export const option = createCrudOption([ export const option = createCrudOption([
{ {
label: '立项申请单号', label: '申请单号',
prop: 'applyNo', prop: 'applyNo',
search: true, search: true,
searchPlaceholder: '请输入', searchPlaceholder: '请输入',
searchOrder: 7, searchOrder: 10,
minWidth: 220, minWidth: 220,
addDisplay: false, addDisplay: false,
editDisabled: true, editDisabled: true,
@@ -115,6 +103,9 @@ export const option = createCrudOption([
{ {
label: '项目编号', label: '项目编号',
prop: 'projectCode', prop: 'projectCode',
search: true,
searchPlaceholder: '请输入',
searchOrder: 5,
minWidth: 150, minWidth: 150,
addDisplay: false, addDisplay: false,
editDisabled: true, editDisabled: true,
@@ -124,7 +115,7 @@ export const option = createCrudOption([
prop: 'projectName', prop: 'projectName',
search: true, search: true,
searchPlaceholder: '请输入', searchPlaceholder: '请输入',
searchOrder: 6, searchOrder: 9,
minWidth: 180, minWidth: 180,
maxlength: 50, maxlength: 50,
rules: textRule('项目名称', 50, true), rules: textRule('项目名称', 50, true),
@@ -151,12 +142,18 @@ export const option = createCrudOption([
{ {
label: '客户名称', label: '客户名称',
prop: 'customerNames', prop: 'customerNames',
search: true,
searchPlaceholder: '请输入',
searchOrder: 6,
minWidth: 180, minWidth: 180,
rules: textRule('客户名称', 255, true), rules: textRule('客户名称', 255, true),
}, },
{ {
label: '下游承运商', label: '下游承运商',
prop: 'carrierNames', prop: 'carrierNames',
search: true,
searchPlaceholder: '请输入',
searchOrder: 7,
minWidth: 180, minWidth: 180,
rules: textRule('下游承运商', 255, true), rules: textRule('下游承运商', 255, true),
}, },
@@ -172,7 +169,7 @@ export const option = createCrudOption([
prop: 'undertakeDeptName', prop: 'undertakeDeptName',
search: true, search: true,
searchPlaceholder: '请输入', searchPlaceholder: '请输入',
searchOrder: 5, searchOrder: 8,
minWidth: 150, minWidth: 150,
rules: textRule('承办部门', 50, true), rules: textRule('承办部门', 50, true),
}, },
@@ -184,26 +181,17 @@ export const option = createCrudOption([
{ {
label: '项目负责人', label: '项目负责人',
prop: 'principalUserName', prop: 'principalUserName',
search: true,
searchPlaceholder: '请输入',
searchOrder: 4,
minWidth: 130, minWidth: 130,
formatter: row => formatUserRealName(row, 'principal'), formatter: row => formatUserRealName(row, 'principal'),
rules: textRule('项目负责人', 50, true), rules: textRule('项目负责人', 50, true),
}, },
{ {
label: '项目负责人', label: '项目负责人ID',
prop: 'principalUserId', prop: 'principalUserId',
type: 'select',
search: true,
searchPlaceholder: '请选择',
searchOrder: 4,
filterable: true,
dicUrl: '/blade-system/user/user-list',
dicFormatter: userDicFormatter,
props: {
label: 'realName',
value: 'id',
},
hide: true, hide: true,
display: false,
}, },
{ {
label: '项目经办人', label: '项目经办人',
+24 -23
View File
@@ -10,7 +10,8 @@
<div class="item" @click="closeAllTags">{{ $t('tagsView.closeAll') }}</div> <div class="item" @click="closeAllTags">{{ $t('tagsView.closeAll') }}</div>
<div class="item" @click="clearCacheTags">{{ $t('tagsView.clearCache') }}</div> <div class="item" @click="clearCacheTags">{{ $t('tagsView.clearCache') }}</div>
</div> </div>
<div class="avue-tags__box"> <!-- <div class="avue-tags__box">-->
<div class="avue-tags__box2">
<el-tabs <el-tabs
v-model="active" v-model="active"
type="card" type="card"
@@ -38,28 +39,28 @@
</template> </template>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<el-dropdown class="avue-tags__menu"> <!-- <el-dropdown class="avue-tags__menu">-->
<el-button type="primary"> <!-- <el-button type="primary">-->
{{ $t('tagsView.menu') }} <!-- {{ $t('tagsView.menu') }}-->
<i class="el-icon-arrow-down el-icon--right"></i> <!-- <i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>-->
</el-button> <!-- </el-button>-->
<template #dropdown> <!-- <template #dropdown>-->
<el-dropdown-menu> <!-- <el-dropdown-menu>-->
<el-dropdown-item @click="openSearch" <!-- <el-dropdown-item @click="openSearch"-->
><i class="icon-fangda" /> {{ $t('tagsView.search') }}</el-dropdown-item <!-- ><i class="icon-fangda" /> {{ $t('tagsView.search') }}</el-dropdown-item-->
> <!-- >-->
<el-dropdown-item @click="closeOthersTags" <!-- <el-dropdown-item @click="closeOthersTags"-->
><i class="icon-fangkuai1" /> {{ $t('tagsView.closeOthers') }} <!-- ><i class="icon-fangkuai1" /> {{ $t('tagsView.closeOthers') }}-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
<el-dropdown-item @click="closeAllTags" <!-- <el-dropdown-item @click="closeAllTags"-->
><i class="icon-cuowukongxin" /> {{ $t('tagsView.closeAll') }}</el-dropdown-item <!-- ><i class="icon-cuowukongxin" /> {{ $t('tagsView.closeAll') }}</el-dropdown-item-->
> <!-- >-->
<el-dropdown-item @click="clearCacheTags" <!-- <el-dropdown-item @click="clearCacheTags"-->
><i class="icon-dingwei" /> {{ $t('tagsView.clearCache') }} <!-- ><i class="icon-dingwei" /> {{ $t('tagsView.clearCache') }}-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
</el-dropdown-menu> <!-- </el-dropdown-menu>-->
</template> <!-- </template>-->
</el-dropdown> <!-- </el-dropdown>-->
</div> </div>
</div> </div>
</template> </template>
+12
View File
@@ -1052,6 +1052,18 @@
.el-form-item--default { .el-form-item--default {
margin-bottom: 14px; margin-bottom: 14px;
} }
// ============ 必填星号 * 与首行文字垂直居中 ============
// Element Plus 默认 .el-form-item__label 为 inline-flex + align-items: flex-start
// 星号 :before 高度(1em) 与文字行盒(line-height) 不一致时,多行/折行 label 会偏上。
// 让 :before 跟随 label 行高、以 inline-block 参与行内对齐即可修复,
// 兼容单行(默认 32px)与多行(auto + 18px)两种 label 高度场景。
// 注:客商档案(customer-archive)的 label 为 auto 高度 + padding 下沉方案,scoped 特异性更高会覆盖本规则。
.el-form-item.is-required .el-form-item__label::before {
display: inline-block;
line-height: inherit;
margin-right: 4px;
}
//.el-form-item { //.el-form-item {
// margin-bottom: 15px !important; // margin-bottom: 15px !important;
//} //}
+41 -15
View File
@@ -18,14 +18,6 @@
@on-load="onLoad" @on-load="onLoad"
> >
<template #menu-left> <template #menu-left>
<el-button
type="primary"
icon="el-icon-plus"
v-if="canMajorProjectSupplement"
@click="openProjectDialog('majorSupplement')"
>
重大项目补录
</el-button>
<el-button <el-button
type="primary" type="primary"
icon="el-icon-plus" icon="el-icon-plus"
@@ -34,6 +26,14 @@
> >
新增 新增
</el-button> </el-button>
<el-button
type="primary"
icon="el-icon-plus"
v-if="canMajorProjectSupplement"
@click="openProjectDialog('majorSupplement')"
>
重大项目补录
</el-button>
<el-button <el-button
type="primary" type="primary"
icon="el-icon-download" icon="el-icon-download"
@@ -120,7 +120,12 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<div v-if="isChangeDialog"></div> <el-form-item v-if="isChangeDialog" label="变更编号" prop="changeNo">
<el-input v-model="form.changeNo" disabled placeholder="系统自动生成" />
</el-form-item>
<el-form-item v-if="isChangeDialog" label="变更日期" prop="changeDate">
<el-input v-model="form.changeDate" disabled placeholder="系统自动生成" />
</el-form-item>
<el-form-item label="项目类型" prop="projectType"> <el-form-item label="项目类型" prop="projectType">
<el-select <el-select
v-model="form.projectType" v-model="form.projectType"
@@ -138,7 +143,11 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="项目编号" prop="projectCode"> <el-form-item label="项目编号" prop="projectCode">
<el-input v-model="form.projectCode" disabled placeholder="系统自动生成" /> <el-input
v-model="form.projectCode"
placeholder="请输入项目编号,不填自动生成"
:disabled="dialogType === 'edit'"
/>
</el-form-item> </el-form-item>
<el-form-item label="项目名称" prop="projectName"> <el-form-item label="项目名称" prop="projectName">
<el-input <el-input
@@ -156,7 +165,7 @@
:disabled="isBasicInfoReadonly" :disabled="isBasicInfoReadonly"
/> />
</el-form-item> </el-form-item>
<el-form-item label="业务部门" prop="businessDeptId"> <el-form-item label="业务部门" prop="businessDeptId" class="project-apply-form__item--full">
<el-tree-select <el-tree-select
v-model="form.businessDeptId" v-model="form.businessDeptId"
:data="businessDeptTreeOptions" :data="businessDeptTreeOptions"
@@ -201,7 +210,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="项目由来说明" prop="sourceRemark"> <el-form-item label="项目由来说明" prop="sourceRemark" class="project-apply-form__item--full">
<el-input v-model="form.sourceRemark" maxlength="300" :disabled="isBasicInfoReadonly" /> <el-input v-model="form.sourceRemark" maxlength="300" :disabled="isBasicInfoReadonly" />
</el-form-item> </el-form-item>
</div> </div>
@@ -790,6 +799,8 @@ const emptyForm = () => ({
projectSource: '商务洽谈', projectSource: '商务洽谈',
sourceRemark: '', sourceRemark: '',
changeType: '', changeType: '',
changeNo: '',
changeDate: '',
customerNames: '', customerNames: '',
carrierNames: '', carrierNames: '',
fundLimit: '', fundLimit: '',
@@ -947,7 +958,6 @@ export default {
{ max: 50, message: '项目名称不能超过50个字符', trigger: 'blur' }, { max: 50, message: '项目名称不能超过50个字符', trigger: 'blur' },
], ],
projectShortName: [ projectShortName: [
{ required: true, message: '请输入项目简称', trigger: 'blur' },
{ max: 20, message: '项目简称不能超过20个字符', trigger: 'blur' }, { max: 20, message: '项目简称不能超过20个字符', trigger: 'blur' },
], ],
businessDeptId: [{ required: true, message: '请选择业务部门', trigger: 'change' }], businessDeptId: [{ required: true, message: '请选择业务部门', trigger: 'change' }],
@@ -1193,9 +1203,12 @@ export default {
} }
this.api.getDetail(id).then(res => { this.api.getDetail(id).then(res => {
const detail = res.data.data || {}; const detail = res.data.data || {};
const isChange = type === 'change';
this.applyProjectDetail({ this.applyProjectDetail({
...detail, ...detail,
changeType: type === 'change' ? this.resolveChangeType(detail) : detail.changeType, changeType: isChange ? this.resolveChangeType(detail) : detail.changeType,
changeNo: isChange ? this.generateChangeNo(detail) : '',
changeDate: isChange ? this.$dayjs().format('YYYY-MM-DD') : '',
}); });
}); });
}, },
@@ -1786,6 +1799,10 @@ export default {
}, },
]; ];
}, },
generateChangeNo(detail) {
const base = detail && detail.projectCode ? detail.projectCode : 'XM';
return `${base}-BG${this.$dayjs().format('YYYYMMDD')}`;
},
handleBusinessDeptChange(value) { handleBusinessDeptChange(value) {
const dept = this.deptOptions.find(item => item.value === value); const dept = this.deptOptions.find(item => item.value === value);
this.form.businessDeptName = dept ? dept.rawLabel : ''; this.form.businessDeptName = dept ? dept.rawLabel : '';
@@ -1803,7 +1820,7 @@ export default {
loadDeptOptions() { loadDeptOptions() {
getDeptTree().then(res => { getDeptTree().then(res => {
const deptTree = res.data.data || []; const deptTree = res.data.data || [];
const businessDeptTree = ['add', 'edit'].includes(this.dialogType) const businessDeptTree = ['add', 'edit', 'majorSupplement'].includes(this.dialogType)
? this.excludeExternalOrganization(deptTree) ? this.excludeExternalOrganization(deptTree)
: deptTree; : deptTree;
const undertakeDeptTree = const undertakeDeptTree =
@@ -2172,6 +2189,15 @@ export default {
min-width: 0 !important; min-width: 0 !important;
white-space: normal; white-space: normal;
} }
// 占满整行的表单项(业务部门 / 项目由来说明)
:deep(.project-apply-form__item--full) {
grid-column: 1 / -1;
.el-form-item__content {
width: 100%;
}
}
} }
&__picker-icon { &__picker-icon {
+25 -2
View File
@@ -806,10 +806,33 @@ export default {
} }
</style> </style>
<style> <style lang="scss">
// 弹窗字段 label 允许多行(列宽不足时换行)
.temporary-credit-limit-dialog .el-form-item__label { .temporary-credit-limit-dialog .el-form-item__label {
white-space: normal; white-space: normal;
line-height: 1.2; line-height: 18px;
}
// 多行 label 时,必填星号与第一行首字严格对齐(不被 form-item align-items:center 拉到中间)
.temporary-credit-limit-dialog {
.el-form-item {
align-items: flex-start; // 改:取消上下居中,星号不再被拉到 label 块中央
}
.el-form-item__label {
height: auto !important;
line-height: 18px;
padding-top: 7px; // 视觉补偿:让单行 label 仍接近 input 中线
}
// 强制必填星号垂直居中于行盒,与第一行汉字字符中心同基线(关键)
.el-form-item.is-required .el-form-item__label::before {
display: inline-block;
line-height: 18px;
height: 18px;
vertical-align: middle; // 关键:相对 baseline 上移,与汉字字符中心对齐
margin-right: 4px;
}
} }
.temporary-credit-limit-dialog .business-crud-page__detail-content .el-descriptions__label { .temporary-credit-limit-dialog .business-crud-page__detail-content .el-descriptions__label {
@@ -174,7 +174,7 @@
:close-on-press-escape="false" :close-on-press-escape="false"
> >
<div class="category-detail"> <div class="category-detail">
<div class="category-line">评分类目{{ currentCategory.categoryName }}</div> <!-- <div class="category-line">评分类目{{ currentCategory.categoryName }}</div>-->
<section-card title="评分项目"> <section-card title="评分项目">
<template #extra> <template #extra>
<el-button <el-button
+47 -18
View File
@@ -1111,12 +1111,12 @@
ref="scoreForm" ref="scoreForm"
:model="currentScore" :model="currentScore"
label-position="right" label-position="right"
label-width="150" label-width="88"
:disabled="readonly" :disabled="readonly"
class="score-detail-form" class="score-detail-form"
> >
<el-row :gutter="42"> <el-row :gutter="42">
<el-col :span="8"> <el-col :span="6">
<el-form-item label="评定日期" required> <el-form-item label="评定日期" required>
<el-date-picker <el-date-picker
v-model="currentScore.scoreDate" v-model="currentScore.scoreDate"
@@ -1125,7 +1125,7 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="拟申请总资金使用额度(万元)" required> <el-form-item label="拟申请总资金使用额度(万元)" required>
<el-input <el-input
v-model="currentScore.applyCreditLimit" v-model="currentScore.applyCreditLimit"
@@ -1134,23 +1134,23 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="最终得分"> <el-form-item label="最终得分">
<el-input :model-value="formatScoreValue(currentScore.finalScore)" disabled /> <el-input :model-value="formatScoreValue(currentScore.finalScore)" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="最大资金使用额度(万元)"> <el-form-item label="最大资金使用额度(万元)">
<el-input :model-value="formatScoreValue(currentScore.maxCreditLimit)" disabled /> <el-input :model-value="formatScoreValue(currentScore.maxCreditLimit)" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="信用等级"> <el-form-item label="信用等级">
<el-input :model-value="formatScoreValue(currentScore.creditLevel)" disabled /> <el-input :model-value="formatScoreValue(currentScore.creditLevel)" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="临时申请额度"> <el-form-item label="临时申请额度(万元)">
<el-input <el-input
v-model="currentScore.tempApplyCreditLimit" v-model="currentScore.tempApplyCreditLimit"
maxlength="18" maxlength="18"
@@ -1158,7 +1158,7 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="临时额度申请使用期限"> <el-form-item label="临时额度申请使用期限">
<div class="score-detail-form__range"> <div class="score-detail-form__range">
<el-date-picker <el-date-picker
@@ -1175,12 +1175,7 @@
</div> </div>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="6">
<el-form-item label="备注">
<el-input v-model="currentScore.remark" maxlength="200" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="评分量化表" required> <el-form-item label="评分量化表" required>
<el-select <el-select
v-model="currentScore.quantificationId" v-model="currentScore.quantificationId"
@@ -1199,6 +1194,11 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="currentScore.remark" maxlength="200" :rows="2" type="textarea" />
</el-form-item>
</el-col>
</el-row> </el-row>
</el-form> </el-form>
@@ -1323,7 +1323,17 @@
{{ row.originalName || row.name || '-' }} {{ row.originalName || row.name || '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="附件描述" prop="description" min-width="220" /> <el-table-column label="附件描述" min-width="220">
<template #default="{ row }">
<el-input
v-if="!readonly"
v-model="row.description"
placeholder="请输入附件描述"
maxlength="200"
/>
<span v-else>{{ row.description || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="文件大小" min-width="120" align="center"> <el-table-column label="文件大小" min-width="120" align="center">
<template #default="{ row }"> <template #default="{ row }">
<span>{{ formatAttachmentSize(row.size) || '-' }}</span> <span>{{ formatAttachmentSize(row.size) || '-' }}</span>
@@ -4657,6 +4667,23 @@ export default {
align-items: center; align-items: center;
} }
// 必填星号 * 与首行文字垂直居中
// Element Plus 的 .el-form-item__label 默认 inline-flex + flex-start
// 多行 label 时 :before 与文字行盒高度不一致导致错位。
// 通过 padding 把内容下沉到 label 中线,让 * 视觉中心落在第一行文字中心。
:deep(.el-form-item.is-required .el-form-item__label) {
align-items: flex-start;
padding-top: 7px;
padding-bottom: 7px;
}
:deep(.el-form-item.is-required .el-form-item__label::before) {
display: inline-block;
height: 18px;
line-height: 18px;
margin-right: 4px;
}
:deep(.el-form-item__content > .el-input), :deep(.el-form-item__content > .el-input),
:deep(.el-form-item__content > .el-select), :deep(.el-form-item__content > .el-select),
:deep(.el-form-item__content > .el-cascader), :deep(.el-form-item__content > .el-cascader),
@@ -4824,13 +4851,15 @@ export default {
:deep(.el-form-item__label) { :deep(.el-form-item__label) {
color: #70757a; color: #70757a;
font-size: 15px; font-size: 15px;
font-weight: 600; white-space: normal;
word-break: break-all;
line-height: 1.4;
} }
:deep(.el-input), :deep(.el-input),
:deep(.el-select), :deep(.el-select),
:deep(.el-date-editor) { :deep(.el-date-editor) {
width: 100%; width: 150px;
} }
} }
+13 -13
View File
@@ -47,26 +47,26 @@ export default ({ mode, command }) => {
__VUE_I18N_LEGACY_API__: true, __VUE_I18N_LEGACY_API__: true,
__INTLIFY_PROD_DEVTOOLS__: false, __INTLIFY_PROD_DEVTOOLS__: false,
}, },
server: {
port: 2888,
proxy: {
'/api': {
target: 'http://localhost',
//target: 'https://saber3.bladex.cn/api',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
},
},
},
// server: { // server: {
// port: 2889, // port: 2888,
// proxy: { // proxy: {
// '/api': { // '/api': {
// target: 'http://172.16.203.228:8000', // target: 'http://localhost',
// //target: 'https://saber3.bladex.cn/api',
// changeOrigin: true, // changeOrigin: true,
// rewrite: path => path.replace(/^\/api/, ''),
// }, // },
// }, // },
// }, // },
server: {
port: 2889,
proxy: {
'/api': {
target: 'http://172.16.203.228:8000',
changeOrigin: true,
},
},
},
resolve: { resolve: {
alias: { alias: {
'~': resolve(__dirname, './'), '~': resolve(__dirname, './'),