20260929172211
This commit is contained in:
1 parent
ebeeca45b6
commit
f337ff1621
16 files changed
+1997
-134
No files matched your search
@@ -1602,6 +1602,7 @@ defineExpose({
|
||||
v-if="views.length || keywordConfig || quickItems.length"
|
||||
class="fms-module-card query-card"
|
||||
>
|
||||
<!-- 页签是「在哪个队列里干活」的上级入口(分组可多行),独占一行 -->
|
||||
<FmsWorkQueueTabs
|
||||
:views="views"
|
||||
:active-codes="viewCodes"
|
||||
@@ -1609,23 +1610,28 @@ defineExpose({
|
||||
@update:active-codes="changeView"
|
||||
@load-counts="requestTabCounts"
|
||||
/>
|
||||
<FmsKeywordSearch
|
||||
v-if="keywordConfig"
|
||||
v-model="keyword"
|
||||
:placeholder="keywordPlaceholder"
|
||||
@search="searchKeyword"
|
||||
/>
|
||||
<FmsQuickFilters
|
||||
v-if="quickItems.length"
|
||||
v-model="quickValues"
|
||||
:items="quickItems"
|
||||
:loading="loading"
|
||||
:advanced-count="appliedFilterCount"
|
||||
:advanced-enabled="moreFilters.length > 0"
|
||||
@search="search"
|
||||
@reset="resetSearch"
|
||||
@open-advanced="openFilters"
|
||||
/>
|
||||
<!-- 条件行:关键词定宽最左,快捷条件横排居中,查询/重置/更多筛选贴右端 -->
|
||||
<div v-if="keywordConfig || quickItems.length" class="query-row">
|
||||
<FmsKeywordSearch
|
||||
v-if="keywordConfig"
|
||||
v-model="keyword"
|
||||
class="query-row__keyword"
|
||||
:placeholder="keywordPlaceholder"
|
||||
@search="searchKeyword"
|
||||
/>
|
||||
<FmsQuickFilters
|
||||
v-if="quickItems.length"
|
||||
class="query-row__quick"
|
||||
v-model="quickValues"
|
||||
:items="quickItems"
|
||||
:loading="loading"
|
||||
:advanced-count="appliedFilterCount"
|
||||
:advanced-enabled="moreFilters.length > 0"
|
||||
@search="search"
|
||||
@reset="resetSearch"
|
||||
@open-advanced="openFilters"
|
||||
/>
|
||||
</div>
|
||||
<FmsActiveFilterPills
|
||||
:pills="activePills"
|
||||
@remove="removePill"
|
||||
@@ -1806,7 +1812,7 @@ defineExpose({
|
||||
box-shadow: 0 2px 6px rgb(31 35 41 / 4%);
|
||||
}
|
||||
|
||||
/* 查询卡:页签 / 关键词 / 快捷筛选 / 条件回显纵向排列,卡间 8px 灰缝由父级 gap 提供 */
|
||||
/* 查询卡:页签 / 条件行 / 条件回显纵向排列,卡间 8px 灰缝由父级 gap 提供 */
|
||||
.query-card {
|
||||
display: flex;
|
||||
flex: none;
|
||||
@@ -1815,6 +1821,27 @@ defineExpose({
|
||||
padding: 10px 16px 12px;
|
||||
}
|
||||
|
||||
/* 条件行:关键词 + 快捷筛选(条件横排 + 动作簇贴右端)同排,页签因此不必跟着条件一起换行。
|
||||
末行对齐:中文横排下关键词与条件同为一行高,末行对齐等于顶对齐;
|
||||
非中文竖排时条件是「label 在上、控件在下」,末行对齐才能让关键词框与控件行齐平 */
|
||||
.query-row {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: flex-end;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* 关键词定宽:不随条件数伸缩,位置跨模块、跨屏宽一致 */
|
||||
.query-row__keyword {
|
||||
flex: none;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.query-row__quick {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 表格卡:工具条 + 表格 + 分页,撑满剩余高度,内部滚动 */
|
||||
.table-card {
|
||||
display: flex;
|
||||
|
||||
@@ -100,55 +100,67 @@ function isDateBeforeLimit(valueToCompare) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 日期预设:语义区间(今天/本周/本月/近三个月)优先,选「自定义」才落到两端日期 -->
|
||||
<FmsField
|
||||
v-if="showDatePreset"
|
||||
v-model="datePreset"
|
||||
class="fms-query-control"
|
||||
type="select"
|
||||
:disabled="disabled"
|
||||
:control-props="{ options: datePresetOptions, filterable: false }"
|
||||
/>
|
||||
<!-- 日期区间:预设下拉与「自定义」的起止两端并排一行。
|
||||
选语义区间时只显示下拉(下拉铺满整格,不留空档),选「自定义」时下拉收窄、两端出现 ——
|
||||
两者不再上下堆叠 -->
|
||||
<div
|
||||
v-if="isRange && (!showDatePreset || datePreset === 'custom')"
|
||||
class="fms-query-control fms-query-control__range"
|
||||
:class="{ 'fms-query-control__range--compact': compact }"
|
||||
v-if="showDatePreset || isRange"
|
||||
class="fms-query-control fms-query-control__row"
|
||||
:class="{ 'fms-query-control__row--preset': showDatePreset }"
|
||||
>
|
||||
<!-- 日期区间:两端是两个独立控件,各自只受另一端约束;不接 enter —— Enter 已被日期面板用于开合 -->
|
||||
<template v-if="isDate">
|
||||
<FmsField
|
||||
v-model="startValue"
|
||||
:type="isDateTime ? 'datetime' : 'date'"
|
||||
:disabled="disabled"
|
||||
:control-props="{
|
||||
...dateFormatProps,
|
||||
timeDefault: 'start',
|
||||
disabledDate: isDateAfterLimit,
|
||||
}"
|
||||
/>
|
||||
<span class="fms-query-control__separator">-</span>
|
||||
<FmsField
|
||||
v-model="endValue"
|
||||
:type="isDateTime ? 'datetime' : 'date'"
|
||||
:disabled="disabled"
|
||||
:control-props="{ ...dateFormatProps, timeDefault: 'end', disabledDate: isDateBeforeLimit }"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<FmsField
|
||||
v-model="startValue"
|
||||
:type="isNumeric ? 'number' : 'input'"
|
||||
:disabled="disabled"
|
||||
@keydown="onEnter"
|
||||
/>
|
||||
<span class="fms-query-control__separator">-</span>
|
||||
<FmsField
|
||||
v-model="endValue"
|
||||
:type="isNumeric ? 'number' : 'input'"
|
||||
:disabled="disabled"
|
||||
@keydown="onEnter"
|
||||
/>
|
||||
</template>
|
||||
<FmsField
|
||||
v-if="showDatePreset"
|
||||
v-model="datePreset"
|
||||
class="fms-query-control__preset"
|
||||
type="select"
|
||||
:disabled="disabled"
|
||||
:control-props="{ options: datePresetOptions, filterable: false }"
|
||||
/>
|
||||
<div
|
||||
v-if="isRange && (!showDatePreset || datePreset === 'custom')"
|
||||
class="fms-query-control__range"
|
||||
:class="{ 'fms-query-control__range--compact': compact }"
|
||||
>
|
||||
<!-- 日期区间:两端是两个独立控件,各自只受另一端约束;不接 enter —— Enter 已被日期面板用于开合 -->
|
||||
<template v-if="isDate">
|
||||
<FmsField
|
||||
v-model="startValue"
|
||||
:type="isDateTime ? 'datetime' : 'date'"
|
||||
:disabled="disabled"
|
||||
:control-props="{
|
||||
...dateFormatProps,
|
||||
timeDefault: 'start',
|
||||
disabledDate: isDateAfterLimit,
|
||||
}"
|
||||
/>
|
||||
<span class="fms-query-control__separator">-</span>
|
||||
<FmsField
|
||||
v-model="endValue"
|
||||
:type="isDateTime ? 'datetime' : 'date'"
|
||||
:disabled="disabled"
|
||||
:control-props="{
|
||||
...dateFormatProps,
|
||||
timeDefault: 'end',
|
||||
disabledDate: isDateBeforeLimit,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<FmsField
|
||||
v-model="startValue"
|
||||
:type="isNumeric ? 'number' : 'input'"
|
||||
:disabled="disabled"
|
||||
@keydown="onEnter"
|
||||
/>
|
||||
<span class="fms-query-control__separator">-</span>
|
||||
<FmsField
|
||||
v-model="endValue"
|
||||
:type="isNumeric ? 'number' : 'input'"
|
||||
:disabled="disabled"
|
||||
@keydown="onEnter"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- checkbox 转三态下拉(全部/是/否):选项与判定逻辑留在本组件,渲染交给 FmsField -->
|
||||
@@ -192,6 +204,27 @@ function isDateBeforeLimit(valueToCompare) {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 条件控件行:并排的预设下拉 + 起止两端(普通区间只有一个子项,等同原来的整格控件) */
|
||||
.fms-query-control__row {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 预设下拉平时铺满整格(选语义区间时没有两端,不留空档);
|
||||
选「自定义」后两端占 70%,下拉收缩到只放得下预设文案。
|
||||
两个子项都经 FmsField 渲染(FmsField 自身不产生元素),用 :deep 命中才稳 */
|
||||
.fms-query-control__row--preset :deep(.fms-query-control__preset) {
|
||||
flex: 1 1 96px;
|
||||
min-width: 96px;
|
||||
}
|
||||
|
||||
.fms-query-control__row--preset :deep(.fms-query-control__range) {
|
||||
flex: 0 1 70%;
|
||||
}
|
||||
|
||||
.fms-query-control__range {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
|
||||
@@ -10,11 +10,19 @@ import { computed } from 'vue'
|
||||
import { ChevronDown, Filter, Search } from '@lucide/vue'
|
||||
import { Button, Form, FormItem } from '@/components/ui'
|
||||
import FmsQueryControl from './FmsQueryControl.vue'
|
||||
import { queryItemLabel } from '@/components/fms-module-common/queryUtils'
|
||||
import {
|
||||
isDateQuery,
|
||||
isRangeQuery,
|
||||
queryItemLabel,
|
||||
} from '@/components/fms-module-common/queryUtils'
|
||||
import { useI18nStore } from '@/stores/i18n'
|
||||
|
||||
/** 条件列宽上限:4 列整行 = 4×288 + 3×16(列间距)= 1200px,不含右侧操作区 */
|
||||
const GRID_MAX_COLUMN_WIDTH = 288
|
||||
/** 单列列宽(px):普通单值控件(input / select / 三态 checkbox)够用即可,不必占满整行 */
|
||||
const COLUMN_WIDTH = 200
|
||||
/** 宽控件占的列数:区间要放下两端,日期区间还要并排放预设下拉,多选的标签也占宽 */
|
||||
const WIDE_COLUMN_SPAN = 2
|
||||
/** 一行最多铺的列数(1 列 = COLUMN_WIDTH),超出换行;与旧系统「定宽列 + 宽控件跨两列」一致 */
|
||||
const MAX_COLUMNS = 4
|
||||
|
||||
const props = defineProps({
|
||||
// 快捷筛选条件项(已按配置顺序排序、已按字段权限裁剪)
|
||||
@@ -35,10 +43,27 @@ const values = computed({
|
||||
set: (next) => emit('update:modelValue', next),
|
||||
})
|
||||
|
||||
/** 网格列数按实际条件数收缩(最多 4 列):只有一两个条件时不应铺满整行 */
|
||||
const gridStyle = computed(() => ({
|
||||
gridTemplateColumns: `repeat(${Math.min(Math.max(props.items.length, 1), 4)}, minmax(0, ${GRID_MAX_COLUMN_WIDTH}px))`,
|
||||
}))
|
||||
/** 控件横向需求大的条件:区间(两端)/ 日期(预设下拉 + 两端)/ 多选(标签占宽) */
|
||||
function needsWideColumn(item) {
|
||||
const multiValue = ['in', 'not_in'].includes(item.config.b_operator)
|
||||
return isRangeQuery(item) || isDateQuery(item) || multiValue
|
||||
}
|
||||
|
||||
/** 栅格列数按各条件占用的列数求和后收缩(最多 MAX_COLUMNS 列):
|
||||
* 只有一两个普通条件时不该铺满整行,宽控件也不会因列数不够被挤到下一行 */
|
||||
const gridStyle = computed(() => {
|
||||
const units = (props.items || []).reduce(
|
||||
(total, item) => total + (needsWideColumn(item) ? WIDE_COLUMN_SPAN : 1),
|
||||
0,
|
||||
)
|
||||
const columns = Math.min(Math.max(units, 1), MAX_COLUMNS)
|
||||
return { gridTemplateColumns: `repeat(${columns}, minmax(0, ${COLUMN_WIDTH}px))` }
|
||||
})
|
||||
|
||||
/** 宽控件跨两列:跨列写在 FormItem 上,栅格才给它两列的位置 */
|
||||
function columnStyleOf(item) {
|
||||
return needsWideColumn(item) ? { gridColumn: `span ${WIDE_COLUMN_SPAN}` } : undefined
|
||||
}
|
||||
|
||||
function labelOf(item) {
|
||||
return item.label || queryItemLabel(item, t)
|
||||
@@ -54,25 +79,32 @@ function submit() {
|
||||
|
||||
<template>
|
||||
<div class="fms-quick-filters">
|
||||
<div class="quick-grid" :style="gridStyle">
|
||||
<Form :model="values" label-width="72px" label-align="right">
|
||||
<FormItem
|
||||
v-for="item in items"
|
||||
:key="item.field.b_field"
|
||||
class="quick-field"
|
||||
:name="item.field.b_field"
|
||||
:label="labelOf(item)"
|
||||
>
|
||||
<FmsQueryControl
|
||||
:model-value="values[item.field.b_field]"
|
||||
:item="item"
|
||||
date-presets
|
||||
@update:model-value="setValue(item.field.b_field, $event)"
|
||||
@enter="submit"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<!-- 栅格落在 Form 自身:FormItem 是它的直接子元素,条件才能横向铺开。
|
||||
若再套一层栅格容器包住 Form,整张表单只是该容器的唯一子项,FormItem 会退回块级纵向堆叠 -->
|
||||
<Form
|
||||
class="quick-grid"
|
||||
:style="gridStyle"
|
||||
:model="values"
|
||||
label-width="72px"
|
||||
label-align="right"
|
||||
>
|
||||
<FormItem
|
||||
v-for="item in items"
|
||||
:key="item.field.b_field"
|
||||
class="quick-field"
|
||||
:style="columnStyleOf(item)"
|
||||
:name="item.field.b_field"
|
||||
:label="labelOf(item)"
|
||||
>
|
||||
<FmsQueryControl
|
||||
:model-value="values[item.field.b_field]"
|
||||
:item="item"
|
||||
date-presets
|
||||
@update:model-value="setValue(item.field.b_field, $event)"
|
||||
@enter="submit"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
||||
<div class="quick-actions">
|
||||
<Button type="primary" :loading="loading" @click="submit">
|
||||
@@ -97,10 +129,12 @@ function submit() {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 末行对齐:中文横排(label 在左)下条件与动作簇同为一行高,末行对齐等于顶对齐;
|
||||
非中文竖排(label 在上)时动作簇才会落到控件那一行的底边,不与 label 平齐 */
|
||||
.fms-quick-filters {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: flex-start;
|
||||
align-items: flex-end;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@@ -109,6 +143,11 @@ function submit() {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
gap: 12px 16px;
|
||||
|
||||
/* 行距只由栅格的 row-gap 提供,取消 FormItem 自带的下间距 */
|
||||
:deep(.fms-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.quick-field) {
|
||||
|
||||
@@ -23,7 +23,8 @@ const props = defineProps({
|
||||
// 是否在非横向虚拟滚动时自动铺满容器;默认按列配置宽度展示。
|
||||
autoFitWidth: { type: Boolean, default: false },
|
||||
// 列宽拖拽默认开启;false=关闭;{ disabled: (col) => boolean }=按列禁用
|
||||
// (铺满容器的弹性列应禁用拖拽,见库文档「列宽铺满容器hack方式」)
|
||||
// (铺满容器的弹性列应禁用拖拽,见库文档「列宽铺满容器hack方式」)。
|
||||
// 列上显式写了 resizable: false 的(操作列、展开列)一律不可拖,无需再传 disabled。
|
||||
colResizable: { type: [Boolean, Object], default: true },
|
||||
// 边框自绘:true=外框圆角描边+行分隔线(默认);false=无外框仅行分隔线(嵌入卡片场景)。
|
||||
// stk-table 库内边框恒为 false,不用其渐变边框。
|
||||
@@ -86,7 +87,24 @@ const tableTheme = computed(() => props.theme ?? (appStore.darkMode ? 'dark' : '
|
||||
// 直接关闭这两个功能。声明了 update:columns emit 后监听器不会进 attrs,
|
||||
// 需从 vnode.props 探测;绑定关系在模板编写时确定,运行期不会变化,无需响应式。
|
||||
const columnsBound = 'onUpdate:columns' in (getCurrentInstance()?.vnode.props ?? {})
|
||||
const effectiveColResizable = columnsBound && !props.autoFitWidth ? props.colResizable : false
|
||||
|
||||
// 列宽拖拽开关:库只提供「全局开关 + disabled(col) 回调」这一种按列控制方式,
|
||||
// 没有按列的 resizable,所以开启时统一转成回调形式,顺带落实列上显式声明的
|
||||
// resizable: false —— 操作列 / 展开列的宽度由代码算(拖了不落库、列重建即丢)。
|
||||
// 必须按列禁掉操作列:它 fixed: 'right' 且左边缘压在最后一列上,库对右侧固定列的
|
||||
// 「左侧把手」拖的是这一列自己,用户拖那根分割线就会改到操作列宽度(拖左列、动操作列)。
|
||||
const effectiveColResizable = (() => {
|
||||
if (!columnsBound || props.autoFitWidth || !props.colResizable) return false
|
||||
const configured = props.colResizable === true ? {} : props.colResizable
|
||||
return {
|
||||
disabled: (column) => {
|
||||
if (column.resizable === false) return true
|
||||
return typeof configured.disabled === 'function'
|
||||
? Boolean(configured.disabled(column))
|
||||
: Boolean(configured.disabled)
|
||||
},
|
||||
}
|
||||
})()
|
||||
|
||||
// Tab 面板从隐藏恢复时,等到容器拥有有效尺寸再刷新虚拟滚动布局。
|
||||
// rAF 将同一帧内的多次 ResizeObserver 通知合并,避免重复重排。
|
||||
@@ -733,7 +751,11 @@ defineExpose({
|
||||
.fms-table__inner.stk-table.bordered-v {
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
background-image: none;
|
||||
/* 只抹掉最右一列的外侧右边线(外框由 .fms-table--bordered 画)。
|
||||
不能整体清空 background-image:库会给「被前面内容穿透遮挡」的右固定列补
|
||||
fixed-cell--border-left,并用 --bg-border-left 画它左边的分隔线;整份清空会
|
||||
把这根线一起干掉,表现为操作列压住内容却没有分割线。 */
|
||||
--bg-border-right: linear-gradient(transparent, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -844,9 +844,10 @@ function openPreview() {
|
||||
</Modal>
|
||||
|
||||
<!-- 预览:上方复刻列表页查询卡(可交互),下方给出生成的查询条件 -->
|
||||
<Modal v-model:open="previewOpen" title="查询预览" width="920px" :footer="false">
|
||||
<Modal v-model:open="previewOpen" title="查询预览" width="1180px" :footer="false">
|
||||
<div class="mm-preview">
|
||||
<div v-if="previewHasEntry" class="mm-preview__card">
|
||||
<!-- 与列表页同排布:页签独占一行,关键词与快捷筛选同行 -->
|
||||
<FmsWorkQueueTabs
|
||||
v-if="previewData.views.length"
|
||||
:views="previewData.views"
|
||||
@@ -855,22 +856,29 @@ function openPreview() {
|
||||
@update:active-codes="previewViewCodes = $event"
|
||||
@load-counts="() => {}"
|
||||
/>
|
||||
<FmsKeywordSearch
|
||||
v-if="previewData.keywordSearch"
|
||||
v-model="previewKeyword"
|
||||
:placeholder="previewKeywordPlaceholder"
|
||||
@search="() => {}"
|
||||
/>
|
||||
<FmsQuickFilters
|
||||
v-if="previewData.quickFilters.length"
|
||||
v-model="previewQuickValues"
|
||||
:items="previewData.quickFilters"
|
||||
:advanced-count="previewFilterCount"
|
||||
:advanced-enabled="previewMoreFilters.length > 0"
|
||||
@search="() => {}"
|
||||
@reset="resetPreviewQuick"
|
||||
@open-advanced="previewFilterOpen = true"
|
||||
/>
|
||||
<div
|
||||
v-if="previewData.keywordSearch || previewData.quickFilters.length"
|
||||
class="mm-preview__row"
|
||||
>
|
||||
<FmsKeywordSearch
|
||||
v-if="previewData.keywordSearch"
|
||||
v-model="previewKeyword"
|
||||
class="mm-preview__keyword"
|
||||
:placeholder="previewKeywordPlaceholder"
|
||||
@search="() => {}"
|
||||
/>
|
||||
<FmsQuickFilters
|
||||
v-if="previewData.quickFilters.length"
|
||||
class="mm-preview__quick"
|
||||
v-model="previewQuickValues"
|
||||
:items="previewData.quickFilters"
|
||||
:advanced-count="previewFilterCount"
|
||||
:advanced-enabled="previewMoreFilters.length > 0"
|
||||
@search="() => {}"
|
||||
@reset="resetPreviewQuick"
|
||||
@open-advanced="previewFilterOpen = true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="mm-preview__empty">当前配置没有产生任何查询入口</p>
|
||||
|
||||
@@ -1157,6 +1165,24 @@ function openPreview() {
|
||||
background: var(--fms-surface);
|
||||
}
|
||||
|
||||
/* 条件行:与列表页查询卡同排布(关键词定宽最左,快捷筛选占满其余,末行对齐) */
|
||||
.mm-preview__row {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: flex-end;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.mm-preview__keyword {
|
||||
flex: none;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.mm-preview__quick {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.mm-preview__empty {
|
||||
margin: 0;
|
||||
color: var(--fms-text-secondary);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Ban, Copy, Eye, Layers, Plus, Send, SquarePen, Trash2 } from '@lucide/vue'
|
||||
import { CircleQuestionMark, Copy, Plus, Trash2 } from '@lucide/vue'
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
Modal,
|
||||
Select,
|
||||
Tabs,
|
||||
Tooltip,
|
||||
} from '@/components/ui'
|
||||
import { FmsModuleListPage } from '@/components/fms-module-list'
|
||||
import { loadDataApi } from '@/services/api'
|
||||
@@ -95,10 +96,11 @@ function openDesign(definitionId) {
|
||||
router.push({ name: 'system-workflow-design', query: { id: definitionId } })
|
||||
}
|
||||
|
||||
/* 操作列只出文字,不带图标:图标会把按钮撑宽、超出操作列的预留宽度 */
|
||||
const definitionRowActions = computed(() => [
|
||||
{ key: 'design', label: '设计', icon: SquarePen, onClick: (row) => openDesign(row.b_id) },
|
||||
{ key: 'versions', label: '版本', icon: Layers, onClick: (row) => openVersionDrawer(row) },
|
||||
{ key: 'delete', label: '删除', icon: Trash2, danger: true, onClick: (row) => handleDeleteDefinition(row) },
|
||||
{ key: 'design', label: '设计', onClick: (row) => openDesign(row.b_id) },
|
||||
{ key: 'versions', label: '版本', onClick: (row) => openVersionDrawer(row) },
|
||||
{ key: 'delete', label: '删除', danger: true, onClick: (row) => handleDeleteDefinition(row) },
|
||||
])
|
||||
|
||||
function handleDeleteDefinition(row) {
|
||||
@@ -239,18 +241,16 @@ function handleRetireVersion(row) {
|
||||
}
|
||||
|
||||
const versionRowActions = computed(() => [
|
||||
{ key: 'design', label: '设计', icon: SquarePen, onClick: (row) => openDesign(row.b_definition_id) },
|
||||
{ key: 'design', label: '设计', onClick: (row) => openDesign(row.b_definition_id) },
|
||||
{
|
||||
key: 'publish',
|
||||
label: '发布',
|
||||
icon: Send,
|
||||
visible: (row) => row.b_status === 'draft',
|
||||
onClick: (row) => handlePublishVersion(row),
|
||||
},
|
||||
{
|
||||
key: 'retire',
|
||||
label: '停用',
|
||||
icon: Ban,
|
||||
danger: true,
|
||||
visible: (row) => row.b_status === 'published',
|
||||
onClick: (row) => handleRetireVersion(row),
|
||||
@@ -414,8 +414,8 @@ function handleBatchDeleteBindings() {
|
||||
}
|
||||
|
||||
const bindingRowActions = computed(() => [
|
||||
{ key: 'edit', label: '编辑', icon: SquarePen, onClick: (row) => openBindingEdit(row) },
|
||||
{ key: 'delete', label: '删除', icon: Trash2, danger: true, onClick: (row) => handleDeleteBinding(row) },
|
||||
{ key: 'edit', label: '编辑', onClick: (row) => openBindingEdit(row) },
|
||||
{ key: 'delete', label: '删除', danger: true, onClick: (row) => handleDeleteBinding(row) },
|
||||
])
|
||||
|
||||
/* ============================================================================
|
||||
@@ -432,7 +432,7 @@ function openInstanceDetail(row) {
|
||||
}
|
||||
|
||||
const instanceRowActions = computed(() => [
|
||||
{ key: 'view', label: '查看', icon: Eye, onClick: (row) => openInstanceDetail(row) },
|
||||
{ key: 'view', label: '查看', onClick: (row) => openInstanceDetail(row) },
|
||||
])
|
||||
</script>
|
||||
|
||||
@@ -511,7 +511,25 @@ const instanceRowActions = computed(() => [
|
||||
<FormItem name="moduleId" label="业务模块" required :span="1">
|
||||
<Select v-model="bindingForm.moduleId" :options="moduleOptions" placeholder="选择要接入审批的模块" />
|
||||
</FormItem>
|
||||
<FormItem name="event" label="业务事件" required :span="1">
|
||||
<!-- 业务事件决定「这次提交走哪条流程」,用 ? 提示解释三种取值,避免和流程内的条件分支混淆 -->
|
||||
<FormItem name="event" required :span="1">
|
||||
<template #label>
|
||||
<span class="wf-binding-event-label">
|
||||
业务事件
|
||||
<Tooltip placement="top">
|
||||
<template #content>
|
||||
<div class="wf-binding-event-tip">
|
||||
<p class="wf-binding-event-tip__title">业务事件决定这次提交走哪条流程:</p>
|
||||
<p><b>送审(submit)</b>:单据第一次提交审批;被驳回结束(作废)后重新发起也走这里。</p>
|
||||
<p><b>重新提交(resubmit)</b>:单据被退回修改后,发起人改完在原单上再次提交。</p>
|
||||
<p><b>变更(change)</b>:单据已审批通过后发生业务变更(如改金额)需再次审批;多数模块用不到。</p>
|
||||
<p class="wf-binding-event-tip__note">一次提交只会命中一条绑定:按「业务模块 + 业务事件 + 条件」匹配,多条命中时取优先级最小的一条。</p>
|
||||
</div>
|
||||
</template>
|
||||
<CircleQuestionMark class="wf-binding-event-help" :size="14" aria-label="业务事件说明" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<Select v-model="bindingForm.event" :options="EVENT_OPTIONS" />
|
||||
</FormItem>
|
||||
<FormItem name="versionId" label="流程版本" required :span="1">
|
||||
@@ -566,8 +584,15 @@ const instanceRowActions = computed(() => [
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 页签栏做成白卡:页面画布是灰底,列表内容是白卡,页签裸在灰底上会显得突兀。
|
||||
左右 8px 内边距 + 标签自身 8px = 下方卡片内容的 16px,保证首项文字左对齐 */
|
||||
.wf-page__nav.tabs {
|
||||
flex: none;
|
||||
padding: 0 8px;
|
||||
margin-bottom: 8px;
|
||||
background: var(--fms-card, #fff);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 6px rgb(31 35 41 / 4%);
|
||||
}
|
||||
|
||||
/* 各页签的列表铺满剩余高度:v-show 切换时只换显示,列表状态与滚动位置都保留 */
|
||||
@@ -588,4 +613,53 @@ const instanceRowActions = computed(() => [
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 「业务事件」标签上的 ? 图标:纯提示,不参与表单校验 */
|
||||
.wf-binding-event-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wf-binding-event-help {
|
||||
/* label 宽固定,图标作为 flex 项会被压缩导致部分被折叠,这里禁止收缩 */
|
||||
flex: none;
|
||||
color: var(--fms-text-secondary);
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* label 文本区默认 overflow: hidden(超长省略号),会把超出固定 label 宽的 ? 图标裁掉 */
|
||||
.fms-form-item[data-field='event'] :deep(.fms-form-label-text) {
|
||||
overflow: visible;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* ---- 业务事件提示浮层排版 ----
|
||||
浮层经 Teleport 渲染到 body,scoped 样式命中不到,故用非 scoped 类;
|
||||
同时清掉 <p> 浏览器默认 margin,否则多行说明会把内容块撑得虚高。 */
|
||||
.wf-binding-event-tip {
|
||||
width: 320px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.wf-binding-event-tip p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wf-binding-event-tip p + p {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.wf-binding-event-tip__title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wf-binding-event-tip__note {
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--fms-border-soft);
|
||||
color: var(--fms-text-secondary);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user