Browse Source

feat: 添加模型删除功能,优化模型参数选择界面

pull/64/head
chenjiale 1 month ago
parent
commit
72c3b1f844
  1. 3
      src/api/alert/model/models.ts
  2. 163
      src/views/model/components/PointTransfer.vue
  3. 26
      src/views/model/components/pointTransferHelper.ts
  4. 143
      src/views/model/list/ModelCard.vue
  5. 192
      src/views/model/list/step/Step3.vue
  6. 48
      src/views/model/list/step/data.tsx
  7. 88
      src/views/model/train/index.vue

3
src/api/alert/model/models.ts

@ -5,6 +5,7 @@ enum Api {
MODEL_CARD_LIST = '/alert/model/card/list', MODEL_CARD_LIST = '/alert/model/card/list',
MODEL_INFO = '/alert/model/info', MODEL_INFO = '/alert/model/info',
MODEL_SAVE = '/alert/model/', MODEL_SAVE = '/alert/model/',
MODEL_DELETE = '/alert/model/',
MODEL_DATA = '/alert/model/data/', MODEL_DATA = '/alert/model/data/',
CALCULATE_BACK = '/alert/model/data/calculate/', CALCULATE_BACK = '/alert/model/data/calculate/',
OPTIMISTIC = '/alert/optimistic', OPTIMISTIC = '/alert/optimistic',
@ -28,6 +29,8 @@ export function modelSaveApi(params?: any) {
return defHttp.post<number>({ url: Api.MODEL_SAVE, data: params }) return defHttp.post<number>({ url: Api.MODEL_SAVE, data: params })
} }
export const modelDeleteApi = (id: number | string) => defHttp.delete<boolean>({ url: `${Api.MODEL_DELETE}${id}` })
export function modelDataApi(id: any, params: any) { export function modelDataApi(id: any, params: any) {
return defHttp.get<any>({ url: Api.MODEL_DATA + id, params }) return defHttp.get<any>({ url: Api.MODEL_DATA + id, params })
} }

163
src/views/model/components/PointTransfer.vue

@ -0,0 +1,163 @@
<script lang="ts" setup>
import type { PropType } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import { Transfer } from 'ant-design-vue'
import type { TransferItem } from 'ant-design-vue'
import { pointListApi } from '@/api/alert/model/select'
import { buildPointKeyFromInfo, buildPointTitle, parsePointKey } from './pointTransferHelper'
interface PointTransferItem extends TransferItem {
key: string
title: string
}
const props = defineProps({
selectedKeys: {
type: Array as PropType<string[]>,
default: () => [],
},
listStyle: {
type: Object as PropType<Record<string, string>>,
default: () => ({
width: '500px',
height: '450px',
}),
},
titles: {
type: Array as PropType<[string, string]>,
default: () => ['可选测点', '已选测点'],
},
showSearch: {
type: Boolean,
default: true,
},
prefillPoints: {
type: Array as PropType<Array<Partial<ReturnType<typeof parsePointKey>>>>,
default: () => [],
},
})
const emit = defineEmits<{
(e: 'update:selectedKeys', value: string[]): void
(e: 'change', value: ReturnType<typeof parsePointKey>[]): void
}>()
const dataSource = ref<PointTransferItem[]>([])
const targetKeys = ref<string[]>([...props.selectedKeys])
const dataMap = computed(() => new Map(dataSource.value.map(item => [item.key, item])))
const prefilledItems = computed<PointTransferItem[]>(() => {
return (props.prefillPoints || []).map((info) => {
const key = buildPointKeyFromInfo(info)
const parsed = parsePointKey(key)
return {
key,
title: buildPointTitle(parsed, key),
}
})
})
function mergeUnique(items: PointTransferItem[]) {
const map = new Map<string, PointTransferItem>()
items.forEach((item) => {
if (item.key === undefined || item.key === null)
return
const key = String(item.key)
if (!map.has(key))
map.set(key, { ...item, key })
})
dataSource.value = Array.from(map.values())
}
function ensureSelectedVisible(keys: string[]) {
mergeUnique(prefilledItems.value)
const missing: PointTransferItem[] = []
keys.forEach((key) => {
const k = String(key)
if (!dataMap.value.has(k)) {
const info = parsePointKey(k)
missing.push({
key: k,
title: buildPointTitle(info, k),
})
}
})
if (missing.length)
mergeUnique([...dataSource.value, ...missing])
}
async function fetchPoints(keyword = '') {
try {
const res = await pointListApi({ keyword })
const fetched = Array.isArray(res)
? res.map((item: any) => {
const key = item?.id
const info = parsePointKey(key)
return {
key: String(key),
title: item?.name || buildPointTitle(info, String(key)),
}
})
: []
const selectedItems = targetKeys.value.map((key) => {
const saved = dataMap.value.get(key)
if (saved)
return saved
const info = parsePointKey(key)
return { key, title: buildPointTitle(info, key) }
})
mergeUnique([...selectedItems, ...fetched])
}
catch (error) {
console.error('获取测点列表失败', error)
}
}
watch(
() => props.selectedKeys,
(val) => {
targetKeys.value = [...val]
ensureSelectedVisible(val)
},
{ immediate: true },
)
function handleChange(nextTargetKeys: string[]) {
targetKeys.value = nextTargetKeys
emit('update:selectedKeys', nextTargetKeys)
emit('change', nextTargetKeys.map(key => parsePointKey(key)))
}
function handleSearch(direction: 'left' | 'right', value: string) {
if (direction === 'left')
fetchPoints(value)
}
function filterOption(inputValue: string, option?: PointTransferItem) {
if (!option?.title)
return false
return option.title.toLowerCase().includes((inputValue || '').toLowerCase())
}
function renderItem(item: PointTransferItem) {
return item.title || (item as any).label || item.key
}
onMounted(() => {
fetchPoints()
})
</script>
<template>
<Transfer
:target-keys="targetKeys"
:data-source="dataSource"
:titles="titles"
:list-style="listStyle"
:show-search="showSearch"
:filter-option="filterOption"
:render="renderItem"
@search="handleSearch"
@change="handleChange"
/>
</template>

26
src/views/model/components/pointTransferHelper.ts

@ -0,0 +1,26 @@
export interface PointKeyInfo {
description: string
pointId: string
unit?: string
Lower?: string
Upper?: string
}
export function parsePointKey(key: string | number | undefined | null): PointKeyInfo {
const safeKey = key !== undefined && key !== null ? String(key) : ''
const [description = '', pointId = '', unit = '', Lower = '', Upper = ''] = safeKey.split('|')
return { description, pointId, unit, Lower, Upper }
}
export function buildPointKeyFromInfo(info: Partial<PointKeyInfo>): string {
const { description = '', pointId = '', unit = '', Lower = '', Upper = '' } = info || {}
return [description, pointId, unit, Lower, Upper].join('|')
}
export function buildPointTitle(info: PointKeyInfo, fallback: string): string {
if (info.description && info.pointId)
return `${info.description} (${info.pointId})`
if (info.description)
return info.description
return fallback
}

143
src/views/model/list/ModelCard.vue

@ -1,14 +1,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Card } from 'ant-design-vue' import { Card, Dropdown, Menu, Popconfirm } from 'ant-design-vue'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import type { ModelItem } from './data' import type { ModelItem } from './data'
import CreateModel from './CreateModel.vue' import CreateModel from './CreateModel.vue'
import Icon from '@/components/Icon/index' import Icon from '@/components/Icon/index'
import { modelCardListApi } from '@/api/alert/model/models' import { modelCardListApi, modelDeleteApi } from '@/api/alert/model/models'
import type { ModelQueryParams } from '@/api/alert/model/model/models' import type { ModelQueryParams } from '@/api/alert/model/model/models'
import { useGo } from '@/hooks/web/usePage' import { useGo } from '@/hooks/web/usePage'
import { useDrawer } from '@/components/Drawer' import { useDrawer } from '@/components/Drawer'
import { useMessage } from '@/hooks/web/useMessage'
const props = defineProps({ const props = defineProps({
loading: { loading: {
@ -23,6 +24,7 @@ const props = defineProps({
}) })
const [registerDraw, { openDrawer }] = useDrawer() const [registerDraw, { openDrawer }] = useDrawer()
const { createMessage } = useMessage()
// //
const go = useGo() const go = useGo()
@ -32,75 +34,106 @@ function changeModel(id, version?) {
} }
const modelCardList = ref<Array<ModelItem>>([]) const modelCardList = ref<Array<ModelItem>>([])
const lastQuery = ref<ModelQueryParams | null>(null)
const colors = ['#8dc63f', '#dbb09e'] const colors = ['#8dc63f', '#dbb09e']
const statusStr = ['未下装', '已下装'] const statusStr = ['未下装', '已下装']
const icons = ['material-symbols:lock-open-right-outline', 'material-symbols:lock-outline'] const icons = ['material-symbols:lock-open-right-outline', 'material-symbols:lock-outline']
const buildQuery = (value: any): ModelQueryParams => ({
unitId: value?.unit,
typeId: value?.type,
systemId: value?.system,
name: value?.name,
})
async function loadModelList(value: any) {
const queryParams = buildQuery(value)
lastQuery.value = queryParams
const modelList = await modelCardListApi(queryParams)
if (!modelList) {
modelCardList.value = []
return
}
const cardList: ModelItem[] = []
for (const modelCard of modelList) {
const statusIndex = Number(modelCard.status) || 0
const card: ModelItem = {
id: modelCard.id,
title: modelCard.name,
version: modelCard.version,
icon: icons[statusIndex],
value: 1,
total: 1,
color: colors[statusIndex],
status: statusStr[statusIndex],
creator: modelCard.creator,
createTime: modelCard.createTime,
description: modelCard.name,
headStyle: {
backgroundColor: colors[statusIndex],
fontSize: '20px',
},
bodyStyle: {
borderColor: colors[statusIndex],
borderWidth: '1px',
},
}
cardList.push(card)
}
modelCardList.value = cardList
}
watch( watch(
() => props.selectData, () => props.selectData,
async (value) => { async (value) => {
const queryParams: ModelQueryParams = { await loadModelList(value)
unitId: value?.unit,
typeId: value?.type,
systemId: value?.system,
name: value?.name,
}
const modelList = await modelCardListApi(queryParams)
if (!modelList) {
modelCardList.value = []
return
}
const cardList: ModelItem[] = []
for (const modelCard of modelList) {
// modelCard.status = 0;
const card: ModelItem = {
id: modelCard.id,
title: modelCard.name,
version: modelCard.version,
icon: icons[modelCard.status],
value: 1,
total: 1,
color: colors[modelCard.status],
status: statusStr[modelCard.status],
creator: modelCard.creator,
createTime: modelCard.createTime,
description: modelCard.name,
headStyle: {
backgroundColor: colors[modelCard.status],
fontSize: '20px',
},
bodyStyle: {
borderColor: colors[modelCard.status],
borderWidth: '1px',
},
}
cardList.push(card)
}
modelCardList.value = cardList
}, },
{ immediate: true },
) )
async function confirmDelete(id: number | string) {
await modelDeleteApi(id)
createMessage.success('删除成功')
await loadModelList(props.selectData)
}
</script> </script>
<template> <template>
<div class="enter-y"> <div class="enter-y">
<div class="grid gap-4 md:grid-cols-4"> <div class="grid gap-4 md:grid-cols-4">
<template v-for="item in modelCardList" :key="item.title"> <template v-for="item in modelCardList" :key="item.title">
<Card <Dropdown :trigger="['contextmenu']">
size="small" <Card
:loading="loading" size="small"
:title="item.title" :loading="loading"
:hoverable="true" :title="item.title"
:body-style="item.bodyStyle" :hoverable="true"
:head-style="item.headStyle" :body-style="item.bodyStyle"
@click="changeModel(item.id, item.version)" :head-style="item.headStyle"
> @click="changeModel(item.id, item.version)"
<template #extra> >
<Icon :icon="item.icon" :size="30" color="white" /> <template #extra>
<Icon :icon="item.icon" :size="30" color="white" />
</template>
<div class="grid p-2 px-5 md:grid-cols-3">
<span>创建人: {{ item.creator }}</span><span>创建时间: {{ item.createTime }}</span><span>模型状态: {{ item.status }}</span>
</div>
</Card>
<template #overlay>
<Menu>
<Menu.Item key="delete">
<Popconfirm
title="确认删除该模型?"
ok-text="删除"
ok-type="danger"
@confirm="() => confirmDelete(item.id)"
>
<span>删除</span>
</Popconfirm>
</Menu.Item>
</Menu>
</template> </template>
<div class="grid p-2 px-5 md:grid-cols-3"> </Dropdown>
<span>创建人: {{ item.creator }}</span><span>创建时间: {{ item.createTime }}</span><span>模型状态: {{ item.status }}</span>
</div>
</Card>
</template> </template>
<Card v-show="systemId != null" size="small" class="icon-card" :hoverable="true" @click="openDrawer(true)"> <Card v-show="systemId != null" size="small" class="icon-card" :hoverable="true" @click="openDrawer(true)">
<Icon icon="ic:sharp-add" :size="80" color="#a7a9a7" /> <Icon icon="ic:sharp-add" :size="80" color="#a7a9a7" />

192
src/views/model/list/step/Step3.vue

@ -1,20 +1,19 @@
<script lang="ts"> <script lang="ts">
import type { PropType } from "vue"; import type { PropType } from 'vue'
import { computed, defineComponent, ref, toRaw, unref } from "vue"; import { defineComponent, ref, toRaw, watch } from 'vue'
import { Alert, Descriptions, Divider } from "ant-design-vue"; import { Alert, Descriptions, Divider } from 'ant-design-vue'
import type { Recordable } from "@vben/types"; import type { Recordable } from '@vben/types'
import { useDebounceFn } from "@vueuse/core"; import { step3Schemas } from './data'
import { step3Schemas } from "./data"; import { BasicForm, useForm } from '@/components/Form'
import { ApiSelect, BasicForm, useForm } from "@/components/Form"; import PointTransfer from '@/views/model/components/PointTransfer.vue'
import { Button } from "@/components/Button"; import { parsePointKey, buildPointKeyFromInfo } from '@/views/model/components/pointTransferHelper'
import { pointListApi } from "@/api/alert/model/select"; import { modelSaveApi } from '@/api/alert/model/models'
import { modelSaveApi } from "@/api/alert/model/models"; import { useMessage } from '@/hooks/web/useMessage'
export default defineComponent({ export default defineComponent({
components: { components: {
Button,
BasicForm, BasicForm,
ApiSelect, PointTransfer,
[Alert.name]: Alert, [Alert.name]: Alert,
[Divider.name]: Divider, [Divider.name]: Divider,
[Descriptions.name]: Descriptions, [Descriptions.name]: Descriptions,
@ -22,140 +21,92 @@ export default defineComponent({
}, },
props: { props: {
beforeData: { beforeData: {
type: Object as PropType<Record<string, any> | null | undefined>, type: Object as PropType<Recordable | null | undefined>,
}, },
systemId: { systemId: {
type: Number, type: Number,
}, },
}, },
emits: ["next", "prev"], emits: ['next', 'prev'],
setup(props, { emit }) { setup(props, { emit }) {
const [ const { createMessage } = useMessage()
register, const selectedKeys = ref<string[]>([])
{ appendSchemaByField, removeSchemaByField, validate, setProps }, const [register, { validate, setProps }] = useForm({
] = useForm({
labelWidth: 100, labelWidth: 100,
schemas: step3Schemas, schemas: step3Schemas,
actionColOptions: { actionColOptions: {
span: 14, span: 14,
}, },
resetButtonOptions: { resetButtonOptions: {
text: "上一步", text: '上一步',
}, },
submitButtonOptions: { submitButtonOptions: {
text: "创建模型", text: '创建模型',
}, },
resetFunc: customResetFunc, resetFunc: customResetFunc,
submitFunc: customSubmitFunc, submitFunc: customSubmitFunc,
}); })
const n = ref(4);
function add() {
appendSchemaByField(
[
{
field: `point${n.value}`,
component: "Input",
label: `参数${n.value}`,
required: true,
slot: "remoteSearch",
colProps: {
span: 23,
},
},
{
field: `${n.value}`,
component: "Input",
label: " ",
slot: "add",
colProps: {
span: 1,
},
},
],
""
);
n.value++;
}
function del(field) { watch(
removeSchemaByField([`point${field}`, `${field}`]); () => props.beforeData?.pointInfo,
n.value--; (val) => {
} if (Array.isArray(val))
selectedKeys.value = val.map(item => buildPointKeyFromInfo(item))
},
{ immediate: true },
)
async function customResetFunc() { async function customResetFunc() {
emit("prev"); emit('prev')
} }
async function customSubmitFunc() { async function customSubmitFunc() {
try { try {
const values = await validate(); await validate()
const pointInfo = []; if (!selectedKeys.value.length) {
for (const key in values) { createMessage.warning('请选择模型参数')
if (key.startsWith("point")) { return
const point = values[key].split("|");
const p = {
description: point[0],
pointId: point[1],
unit: point[2],
Lower: point[3],
Upper: point[4],
dead: true,
limit: false,
};
pointInfo.push(p);
}
} }
const modelInfo = toRaw(props.beforeData); const pointInfo = selectedKeys.value.map((key) => {
modelInfo.pointInfo = pointInfo; const point = parsePointKey(key)
const modelId = await modelSaveApi(modelInfo); return {
description: point.description,
pointId: point.pointId,
unit: point.unit,
Lower: point.Lower,
Upper: point.Upper,
dead: true,
limit: false,
}
})
const modelInfo = toRaw(props.beforeData) || {}
modelInfo.pointInfo = pointInfo
setProps({ setProps({
submitButtonOptions: { submitButtonOptions: {
loading: true, loading: true,
}, },
}); })
setTimeout(() => { const modelId = await modelSaveApi(modelInfo)
setProps({ emit('next', modelId)
submitButtonOptions: {
loading: false,
},
});
emit("next", modelId);
}, 1500);
} catch (error) {
console.error(error);
} }
} catch (error) {
console.error(error)
const keyword = ref<string>(""); }
const searchParams = computed<Recordable>(() => { finally {
return { keyword: unref(keyword) }; setProps({
}); submitButtonOptions: {
loading: false,
function onSearch(value: string) { },
keyword.value = value; })
}
async function searchPoint(params) {
if (params.keyword) {
const data = await pointListApi(params);
return data;
} }
} }
return { return {
register, register,
del, selectedKeys,
add, }
onSearch: useDebounceFn(onSearch, 300),
searchParams,
searchPoint,
handleReset: () => {
keyword.value = "";
},
};
}, },
}); })
</script> </script>
<template> <template>
@ -180,30 +131,19 @@ export default defineComponent({
</a-descriptions> </a-descriptions>
<a-divider /> <a-divider />
<BasicForm @register="register"> <BasicForm @register="register">
<template #remoteSearch="{ model, field }"> <template #pointTransfer>
<ApiSelect <PointTransfer
v-model:value="model[field]" v-model:selected-keys="selectedKeys"
:api="searchPoint" :prefill-points="beforeData?.pointInfo || []"
show-search
:filter-option="false"
result-field="list"
label-field="name"
value-field="id"
:params="searchParams"
@search="onSearch"
/> />
</template> </template>
<template #add="{ field }">
<Button v-if="Number(field) === 0" @click="add"> + </Button>
<Button v-if="field > 0" @click="del(field)"> - </Button>
</template>
</BasicForm> </BasicForm>
</div> </div>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
.step3 { .step3 {
width: 450px; max-width: 1100px;
margin: 0 auto; margin: 0 auto;
} }
</style> </style>

48
src/views/model/list/step/data.tsx

@ -83,51 +83,13 @@ export const step2Schemas: FormSchema[] = [
export const step3Schemas: FormSchema[] = [ export const step3Schemas: FormSchema[] = [
{ {
field: 'point0', field: 'pointTransfer',
component: 'Input', component: 'Input',
label: '参数1', label: '参数选择',
required: true, slot: 'pointTransfer',
slot: 'remoteSearch',
componentProps: {
style: { width: '180px' },
},
colProps: { colProps: {
span: 23, span: 24,
},
},
{
field: 'point1',
component: 'Input',
label: '参数2',
required: true,
slot: 'remoteSearch',
componentProps: {
style: { width: '180px' },
},
colProps: {
span: 23,
},
},
{
field: 'point2',
component: 'Input',
label: '参数3',
required: true,
slot: 'remoteSearch',
componentProps: {
style: { width: '180px' },
},
colProps: {
span: 23,
},
},
{
field: '0',
component: 'Input',
label: ' ',
slot: 'add',
colProps: {
span: 1,
}, },
labelWidth: 120,
}, },
] ]

88
src/views/model/train/index.vue

@ -25,7 +25,6 @@ import {
Steps, Steps,
Table, Table,
Tabs, Tabs,
Transfer,
} from 'ant-design-vue' } from 'ant-design-vue'
import VueECharts from 'vue-echarts' import VueECharts from 'vue-echarts'
import { pointTableSchema, sampleInfoTableSchema } from './data' import { pointTableSchema, sampleInfoTableSchema } from './data'
@ -45,9 +44,10 @@ import type { AssessReportSimple } from '@/api/alert/model/model/assessReportMod
import { getExaHistorys } from '@/api/alert/exa/index' import { getExaHistorys } from '@/api/alert/exa/index'
import { useECharts } from '@/hooks/web/useECharts' import { useECharts } from '@/hooks/web/useECharts'
import { useMessage } from '@/hooks/web/useMessage' import { useMessage } from '@/hooks/web/useMessage'
import { pointListApi } from '@/api/alert/model/select'
import { useGo } from '@/hooks/web/usePage' import { useGo } from '@/hooks/web/usePage'
import Icon from '@/components/Icon' import Icon from '@/components/Icon'
import PointTransfer from '../components/PointTransfer.vue'
import { buildPointKeyFromInfo, parsePointKey } from '../components/pointTransferHelper'
export default defineComponent({ export default defineComponent({
components: { components: {
@ -72,12 +72,12 @@ export default defineComponent({
AInputNumber: InputNumber, AInputNumber: InputNumber,
AButton: Button, AButton: Button,
ASpin: Spin, ASpin: Spin,
ATransfer: Transfer,
ARow: Row, ARow: Row,
ACol: Col, ACol: Col,
ASelect: Select, ASelect: Select,
ASpace: Space, ASpace: Space,
Icon, Icon,
PointTransfer,
}, },
setup() { setup() {
const { createMessage } = useMessage() const { createMessage } = useMessage()
@ -710,6 +710,7 @@ export default defineComponent({
alarmname: '全工况运行', alarmname: '全工况运行',
}) })
const openEditModeModal = ref<boolean>(false) const openEditModeModal = ref<boolean>(false)
const normalizeVersion = (val?: string | null) => (val ? String(val).trim().toLowerCase() : '')
function openEditMode() { function openEditMode() {
if (!canEditModel.value) { if (!canEditModel.value) {
@ -739,46 +740,6 @@ export default defineComponent({
selectedKeys: [], selectedKeys: [],
}) })
// 穿
const transferData = ref([]) // 穿
//
async function fetchAllPoints(keyword = '') {
// keyword
// const res = await fetchPointsApi({ keyword })
//
const data = await pointListApi({ keyword })
console.log('Fetched points:', data)
transferData.value = transferData.value.filter(item => editModelForm.value.selectedKeys.includes(item.key))
.concat(data.map(item => ({
key: item.id,
title: item.name,
})))
console.log('Transfer data:', transferData.value)
}
onMounted(() => {
fetchAllPoints()
})
function handleTransferSearch(dir, value) {
if (dir === 'left') {
//
fetchAllPoints(value)
}
else {
//
transferData.value = (model.value?.pointInfo || [])
.filter(item =>
editModelForm.value.selectedKeys.includes(`${item.description}|${item.pointId}|${item.unit}|${item.Lower}|${item.Upper}`)
&& (`${item.description || ''}(${item.pointId})`).includes(value),
)
.map(item => ({
key: `${item.description}|${item.pointId}|${item.unit}|${item.Lower}|${item.Upper}`,
title: `${item.description || ''} (${item.pointId})`,
}))
}
}
function openEditModel() { function openEditModel() {
if (!canEditModel.value) { if (!canEditModel.value) {
createMessage.warning('非草稿版本不可修改模型') createMessage.warning('非草稿版本不可修改模型')
@ -786,12 +747,13 @@ export default defineComponent({
} }
editModelForm.value.sampling = model.value?.sampling || 0 editModelForm.value.sampling = model.value?.sampling || 0
editModelForm.value.rate = model.value?.rate || 0 editModelForm.value.rate = model.value?.rate || 0
editModelForm.value.selectedKeys = (model.value?.pointInfo || []).map(item => `${item.description}|${item.pointId}|${item.unit}|${item.Lower}|${item.Upper}`) editModelForm.value.selectedKeys = (model.value?.pointInfo || []).map(item => buildPointKeyFromInfo({
transferData.value = (model.value?.pointInfo || []).map(item => ({ description: item.description ?? item.Description,
key: `${item.description}|${item.pointId}|${item.unit}|${item.Lower}|${item.Upper}`, pointId: item.pointId ?? item.PointId,
title: `${item.description || ''} (${item.pointId})`, unit: item.unit ?? item.Unit,
Lower: item.Lower ?? item.lower,
Upper: item.Upper ?? item.upper,
})) }))
console.log('transferData:', transferData.value)
openEditModelModal.value = true openEditModelModal.value = true
} }
function handleEditModelOk() { function handleEditModelOk() {
@ -802,7 +764,7 @@ export default defineComponent({
model.value.sampling = editModelForm.value.sampling model.value.sampling = editModelForm.value.sampling
model.value.rate = editModelForm.value.rate model.value.rate = editModelForm.value.rate
model.value.pointInfo = editModelForm.value.selectedKeys.map((key) => { model.value.pointInfo = editModelForm.value.selectedKeys.map((key) => {
const [description, pointId, unit, Lower, Upper] = key.split('|') const { description, pointId, unit, Lower, Upper } = parsePointKey(key)
return { return {
description, description,
pointId, pointId,
@ -828,12 +790,13 @@ export default defineComponent({
const reportNameOptions = ref<{ label: string, value: number }[]>([]) const reportNameOptions = ref<{ label: string, value: number }[]>([])
const reportNameSelectVisible = ref(false) const reportNameSelectVisible = ref(false)
const selectedReportNameId = ref<number | null>(null) const selectedReportNameId = ref<number | null>(null)
const isVTestVersion = computed( const isVTestVersion = computed(() => {
() => (model.value?.Cur_Version || model.value?.version) === 'v-test', const version = normalizeVersion(model.value?.Cur_Version || model.value?.version)
) return version === '' || version === 'v-test'
})
const canEditModel = computed(() => { const canEditModel = computed(() => {
const version = selectedVersion.value || model.value?.Cur_Version || model.value?.version const version = normalizeVersion(selectedVersion.value || model.value?.Cur_Version || model.value?.version)
return version === 'v-test' return version === '' || version === 'v-test'
}) })
const isBottomed = computed(() => model.value?.btmState === '已下装') const isBottomed = computed(() => model.value?.btmState === '已下装')
const reportColumns = [ const reportColumns = [
@ -1032,6 +995,7 @@ export default defineComponent({
} }
return { return {
normalizeVersion,
pointTable, pointTable,
model, model,
selectedVersion, selectedVersion,
@ -1064,8 +1028,6 @@ export default defineComponent({
clearModel, clearModel,
openEditModelModal, openEditModelModal,
editModelForm, editModelForm,
transferData,
handleTransferSearch,
openEditModel, openEditModel,
handleEditModelOk, handleEditModelOk,
handleEditModelCancel, handleEditModelCancel,
@ -1442,21 +1404,13 @@ export default defineComponent({
</a-col> </a-col>
</a-row> </a-row>
<div style="display: flex; justify-content: center; margin-top: 24px;margin-bottom: 10px;"> <div style="display: flex; justify-content: center; margin-top: 24px;margin-bottom: 10px;">
<a-transfer <PointTransfer
v-model:target-keys="editModelForm.selectedKeys" v-model:selected-keys="editModelForm.selectedKeys"
:data-source="transferData" :prefill-points="model?.pointInfo || []"
:render="item => item.title"
:row-key="(item) => item.key"
:pagination="false"
:show-search="true"
:filter="true"
search-placeholder="搜索测点"
:titles="['可选测点', '已选测点']"
:list-style="{ :list-style="{
width: '500px', width: '500px',
height: '450px', height: '450px',
}" }"
@search="handleTransferSearch"
/> />
</div> </div>
</a-form> </a-form>

Loading…
Cancel
Save