Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
commit
fb2595ef90
|
|
@ -6,7 +6,7 @@ runs:
|
|||
using: 'composite'
|
||||
steps:
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
uses: pnpm/action-setup@v6
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v6
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v5
|
||||
uses: pnpm/action-setup@v6
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
run: pnpm build:play
|
||||
|
||||
- name: Sync Playground files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_PLAYGROUND_FTP_ACCOUNT }}
|
||||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
run: pnpm build:docs
|
||||
|
||||
- name: Sync Docs files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEBSITE_FTP_ACCOUNT }}
|
||||
|
|
@ -85,7 +85,7 @@ jobs:
|
|||
run: pnpm run build:antd
|
||||
|
||||
- name: Sync files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_ANTD_FTP_ACCOUNT }}
|
||||
|
|
@ -116,7 +116,7 @@ jobs:
|
|||
run: pnpm run build:ele
|
||||
|
||||
- name: Sync files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_ELE_FTP_ACCOUNT }}
|
||||
|
|
@ -147,7 +147,7 @@ jobs:
|
|||
run: pnpm run build:naive
|
||||
|
||||
- name: Sync files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_NAIVE_FTP_ACCOUNT }}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
steps:
|
||||
- name: remove enhancement pending
|
||||
if: github.event.label.name == 'enhancement'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
uses: actions-cool/issues-helper-backup@d65454423c6fbbd20026b9b499d403f79422ac69
|
||||
with:
|
||||
actions: 'remove-labels'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
|
||||
- name: remove bug pending
|
||||
if: github.event.label.name == 'bug'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
uses: actions-cool/issues-helper-backup@d65454423c6fbbd20026b9b499d403f79422ac69
|
||||
with:
|
||||
actions: 'remove-labels'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -36,7 +36,7 @@ jobs:
|
|||
|
||||
- name: needs reproduction
|
||||
if: github.event.label.name == 'needs reproduction'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
uses: actions-cool/issues-helper-backup@d65454423c6fbbd20026b9b499d403f79422ac69
|
||||
with:
|
||||
actions: 'create-comment, remove-labels'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -3,60 +3,44 @@ name: Create Release Tag
|
|||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
|
||||
env:
|
||||
HUSKY: '0'
|
||||
- 'v*.*.*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Tag to create (e.g. v1.2.3)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
release:
|
||||
name: Create Release
|
||||
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [22]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# - name: Checkout code
|
||||
# uses: actions/checkout@v6
|
||||
# with:
|
||||
# fetch-depth: 0
|
||||
|
||||
# - name: Install pnpm
|
||||
# uses: pnpm/action-setup@v4
|
||||
|
||||
# - name: Use Node.js ${{ matrix.node-version }}
|
||||
# uses: actions/setup-node@v4
|
||||
# with:
|
||||
# node-version: ${{ matrix.node-version }}
|
||||
# cache: "pnpm"
|
||||
|
||||
# - name: Install dependencies
|
||||
# run: pnpm install --frozen-lockfile
|
||||
|
||||
# - name: Test and Build
|
||||
# run: |
|
||||
# pnpm run test
|
||||
# pnpm run build
|
||||
|
||||
- name: version
|
||||
- name: Extract version
|
||||
id: version
|
||||
run: |
|
||||
tag=${GITHUB_REF/refs\/tags\//}
|
||||
version=${tag#v}
|
||||
major=${version%%.*}
|
||||
echo "tag=${tag}" >> $GITHUB_OUTPUT
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
echo "major=${major}" >> $GITHUB_OUTPUT
|
||||
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
raw_tag="${{ inputs.tag }}"
|
||||
else
|
||||
raw_tag="${GITHUB_REF_NAME}"
|
||||
fi
|
||||
# Normalize: ensure v prefix
|
||||
tag="${raw_tag}"
|
||||
[[ "${tag:0:1}" != "v" ]] && tag="v${tag}"
|
||||
version="${tag#v}"
|
||||
major="${version%%.*}"
|
||||
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
|
||||
echo "version=${version}" >> "${GITHUB_OUTPUT}"
|
||||
echo "major=${major}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- uses: release-drafter/release-drafter@v7
|
||||
with:
|
||||
|
|
@ -64,17 +48,3 @@ jobs:
|
|||
publish: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# - name: force update major tag
|
||||
# run: |
|
||||
# git tag v${{ steps.version.outputs.major }} ${{ steps.version.outputs.tag }} -f
|
||||
# git push origin refs/tags/v${{ steps.version.outputs.major }} -f
|
||||
|
||||
# - name: Create Release for Tag
|
||||
# id: release_tag
|
||||
# uses: ncipollo/release-action@v1
|
||||
# with:
|
||||
# token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# generateReleaseNotes: "true"
|
||||
# body: |
|
||||
# > Please refer to [CHANGELOG.md](https://github.com/vbenjs/vue-vben-admin/blob/main/CHANGELOG.md) for details.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ package-lock.json
|
|||
.VSCodeCounter
|
||||
**/backend-mock/data
|
||||
.omx
|
||||
.pnpm-store
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
|
@ -57,3 +58,5 @@ vite.config.ts.*
|
|||
.claude
|
||||
.codex
|
||||
skills-lock.json
|
||||
.atomcode
|
||||
datalog
|
||||
|
|
|
|||
12
.npmrc
12
.npmrc
|
|
@ -1,13 +1 @@
|
|||
registry=https://registry.npmmirror.com
|
||||
public-hoist-pattern[]=lefthook
|
||||
public-hoist-pattern[]=eslint
|
||||
public-hoist-pattern[]=oxfmt
|
||||
public-hoist-pattern[]=oxlint
|
||||
public-hoist-pattern[]=stylelint
|
||||
public-hoist-pattern[]=*postcss*
|
||||
public-hoist-pattern[]=@commitlint/*
|
||||
public-hoist-pattern[]=czg
|
||||
|
||||
strict-peer-dependencies=false
|
||||
auto-install-peers=true
|
||||
dedupe-peer-dependents=true
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
// lint && format
|
||||
"oxc.enable": true,
|
||||
"oxc.typeAware": true,
|
||||
"oxc.typeAware": false,
|
||||
"oxc.configPath": "oxlint.config.ts",
|
||||
"oxc.fmt.configPath": "oxfmt.config.ts",
|
||||
"eslint.useFlatConfig": true,
|
||||
|
|
|
|||
|
|
@ -136,8 +136,8 @@ const PreviewGroup = defineAsyncComponent(() =>
|
|||
import('ant-design-vue/es/image').then((res) => res.ImagePreviewGroup),
|
||||
);
|
||||
|
||||
const withDefaultPlaceholder = <T extends Component>(
|
||||
component: T,
|
||||
const withDefaultPlaceholder = (
|
||||
component: Component,
|
||||
type: 'input' | 'select',
|
||||
componentProps: Recordable<any> = {},
|
||||
) => {
|
||||
|
|
@ -711,7 +711,9 @@ async function initComponentAdapter() {
|
|||
modelValueProp: 'value',
|
||||
}),
|
||||
Input: withDefaultPlaceholder(Input, 'input'),
|
||||
InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
|
||||
InputNumber: withDefaultPlaceholder(InputNumber, 'input', {
|
||||
style: { width: '100%' },
|
||||
}),
|
||||
InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
|
||||
Mentions: withDefaultPlaceholder(Mentions, 'input'),
|
||||
// 自定义主要按钮
|
||||
|
|
|
|||
|
|
@ -150,14 +150,14 @@ export function getDataSinkPage(params: PageParam) {
|
|||
|
||||
/** 查询数据流转目的详情 */
|
||||
export function getDataSink(id: number) {
|
||||
return requestClient.get<DataSinkApi.DataSink>(
|
||||
`/iot/data-sink/get?id=${id}`,
|
||||
);
|
||||
return requestClient.get<DataSinkApi.DataSink>(`/iot/data-sink/get?id=${id}`);
|
||||
}
|
||||
|
||||
/** 查询数据流转目的(精简)列表 */
|
||||
export function getDataSinkSimpleList() {
|
||||
return requestClient.get<DataSinkApi.DataSink[]>('/iot/data-sink/simple-list');
|
||||
return requestClient.get<DataSinkApi.DataSink[]>(
|
||||
'/iot/data-sink/simple-list',
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增数据流转目的 */
|
||||
|
|
|
|||
|
|
@ -195,7 +195,9 @@ export const ThingModelFormRules: Record<string, Rule[]> = {
|
|||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
accessMode: [{ required: true, message: '请选择读写类型', trigger: 'change' }],
|
||||
accessMode: [
|
||||
{ required: true, message: '请选择读写类型', trigger: 'change' },
|
||||
],
|
||||
callType: [{ required: true, message: '请选择调用方式', trigger: 'change' }],
|
||||
eventType: [{ required: true, message: '请选择事件类型', trigger: 'change' }],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,5 +20,8 @@ export namespace MesCalCalendarApi {
|
|||
|
||||
/** 查询排班日历列表 */
|
||||
export function getCalendarList(params: any) {
|
||||
return requestClient.get<MesCalCalendarApi.CalendarDay[]>('/mes/cal/calendar/list', { params });
|
||||
return requestClient.get<MesCalCalendarApi.CalendarDay[]>(
|
||||
'/mes/cal/calendar/list',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,18 @@ export namespace MesCalHolidayApi {
|
|||
|
||||
/** 查询假期设置列表 */
|
||||
export function getHolidayList(params?: MesCalHolidayApi.HolidayQuery) {
|
||||
return requestClient.get<MesCalHolidayApi.Holiday[]>('/mes/cal/holiday/list', { params });
|
||||
return requestClient.get<MesCalHolidayApi.Holiday[]>(
|
||||
'/mes/cal/holiday/list',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 根据日期查询假期设置 */
|
||||
export function getHolidayByDay(day: string) {
|
||||
return requestClient.get<MesCalHolidayApi.Holiday>('/mes/cal/holiday/get-by-day', { params: { day } });
|
||||
return requestClient.get<MesCalHolidayApi.Holiday>(
|
||||
'/mes/cal/holiday/get-by-day',
|
||||
{ params: { day } },
|
||||
);
|
||||
}
|
||||
|
||||
/** 保存假期设置 */
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ export namespace MesCalPlanApi {
|
|||
|
||||
/** 查询排班计划分页 */
|
||||
export function getPlanPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesCalPlanApi.Plan>>('/mes/cal/plan/page', { params });
|
||||
return requestClient.get<PageResult<MesCalPlanApi.Plan>>(
|
||||
'/mes/cal/plan/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询排班计划详情 */
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ export namespace MesCalPlanShiftApi {
|
|||
|
||||
/** 查询指定排班计划的班次列表 */
|
||||
export function getPlanShiftListByPlan(planId: number) {
|
||||
return requestClient.get<MesCalPlanShiftApi.PlanShift[]>(`/mes/cal/plan-shift/list-by-plan?planId=${planId}`);
|
||||
return requestClient.get<MesCalPlanShiftApi.PlanShift[]>(
|
||||
`/mes/cal/plan-shift/list-by-plan?planId=${planId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增计划班次 */
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ export namespace MesCalPlanTeamApi {
|
|||
|
||||
/** 查询指定排班计划的班组列表 */
|
||||
export function getPlanTeamListByPlan(planId: number) {
|
||||
return requestClient.get<MesCalPlanTeamApi.PlanTeam[]>(`/mes/cal/plan-team/list-by-plan?planId=${planId}`);
|
||||
return requestClient.get<MesCalPlanTeamApi.PlanTeam[]>(
|
||||
`/mes/cal/plan-team/list-by-plan?planId=${planId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增计划班组关联 */
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@ export namespace MesCalTeamApi {
|
|||
|
||||
/** 查询班组分页 */
|
||||
export function getTeamPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesCalTeamApi.Team>>('/mes/cal/team/page', { params });
|
||||
return requestClient.get<PageResult<MesCalTeamApi.Team>>(
|
||||
'/mes/cal/team/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询班组列表 */
|
||||
|
|
|
|||
|
|
@ -26,17 +26,26 @@ export function deleteTeamMember(id: number) {
|
|||
|
||||
/** 查询班组成员分页 */
|
||||
export function getTeamMemberPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesCalTeamMemberApi.TeamMember>>('/mes/cal/team-member/page', { params });
|
||||
return requestClient.get<PageResult<MesCalTeamMemberApi.TeamMember>>(
|
||||
'/mes/cal/team-member/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询指定班组的成员列表 */
|
||||
export function getTeamMemberListByTeam(teamId: number) {
|
||||
return requestClient.get<MesCalTeamMemberApi.TeamMember[]>('/mes/cal/team-member/list-by-team', { params: { teamId } });
|
||||
return requestClient.get<MesCalTeamMemberApi.TeamMember[]>(
|
||||
'/mes/cal/team-member/list-by-team',
|
||||
{ params: { teamId } },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询多个班组的成员列表 */
|
||||
export function getTeamMemberListByTeamIds(teamIds: number[]) {
|
||||
return requestClient.get<MesCalTeamMemberApi.TeamMember[]>('/mes/cal/team-member/list-by-team', {
|
||||
params: { teamIds: teamIds.join(',') },
|
||||
});
|
||||
return requestClient.get<MesCalTeamMemberApi.TeamMember[]>(
|
||||
'/mes/cal/team-member/list-by-team',
|
||||
{
|
||||
params: { teamIds: teamIds.join(',') },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,17 @@ export namespace MesDvCheckPlanApi {
|
|||
|
||||
/** 查询点检保养方案分页 */
|
||||
export function getCheckPlanPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvCheckPlanApi.CheckPlan>>('/mes/dv/check-plan/page', { params });
|
||||
return requestClient.get<PageResult<MesDvCheckPlanApi.CheckPlan>>(
|
||||
'/mes/dv/check-plan/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询点检保养方案详情 */
|
||||
export function getCheckPlan(id: number) {
|
||||
return requestClient.get<MesDvCheckPlanApi.CheckPlan>(`/mes/dv/check-plan/get?id=${id}`);
|
||||
return requestClient.get<MesDvCheckPlanApi.CheckPlan>(
|
||||
`/mes/dv/check-plan/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增点检保养方案 */
|
||||
|
|
|
|||
|
|
@ -16,11 +16,15 @@ export namespace MesDvCheckPlanMachineryApi {
|
|||
|
||||
/** 查询指定方案的设备列表 */
|
||||
export function getCheckPlanMachineryListByPlan(planId: number) {
|
||||
return requestClient.get<MesDvCheckPlanMachineryApi.CheckPlanMachinery[]>(`/mes/dv/check-plan-machinery/list-by-plan?planId=${planId}`);
|
||||
return requestClient.get<MesDvCheckPlanMachineryApi.CheckPlanMachinery[]>(
|
||||
`/mes/dv/check-plan-machinery/list-by-plan?planId=${planId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增方案设备关联 */
|
||||
export function createCheckPlanMachinery(data: MesDvCheckPlanMachineryApi.CheckPlanMachinery) {
|
||||
export function createCheckPlanMachinery(
|
||||
data: MesDvCheckPlanMachineryApi.CheckPlanMachinery,
|
||||
) {
|
||||
return requestClient.post('/mes/dv/check-plan-machinery/create', data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@ export namespace MesDvCheckPlanSubjectApi {
|
|||
|
||||
/** 查询指定方案的项目列表 */
|
||||
export function getCheckPlanSubjectListByPlan(planId: number) {
|
||||
return requestClient.get<MesDvCheckPlanSubjectApi.CheckPlanSubject[]>(`/mes/dv/check-plan-subject/list-by-plan?planId=${planId}`);
|
||||
return requestClient.get<MesDvCheckPlanSubjectApi.CheckPlanSubject[]>(
|
||||
`/mes/dv/check-plan-subject/list-by-plan?planId=${planId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增方案项目关联 */
|
||||
export function createCheckPlanSubject(data: MesDvCheckPlanSubjectApi.CheckPlanSubject) {
|
||||
export function createCheckPlanSubject(
|
||||
data: MesDvCheckPlanSubjectApi.CheckPlanSubject,
|
||||
) {
|
||||
return requestClient.post('/mes/dv/check-plan-subject/create', data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,17 @@ export namespace MesDvCheckRecordApi {
|
|||
|
||||
/** 查询设备点检记录分页 */
|
||||
export function getCheckRecordPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvCheckRecordApi.CheckRecord>>('/mes/dv/check-record/page', { params });
|
||||
return requestClient.get<PageResult<MesDvCheckRecordApi.CheckRecord>>(
|
||||
'/mes/dv/check-record/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备点检记录详情 */
|
||||
export function getCheckRecord(id: number) {
|
||||
return requestClient.get<MesDvCheckRecordApi.CheckRecord>(`/mes/dv/check-record/get?id=${id}`);
|
||||
return requestClient.get<MesDvCheckRecordApi.CheckRecord>(
|
||||
`/mes/dv/check-record/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增设备点检记录 */
|
||||
|
|
@ -54,5 +59,7 @@ export function deleteCheckRecord(id: number) {
|
|||
|
||||
/** 导出设备点检记录 */
|
||||
export function exportCheckRecord(params: any) {
|
||||
return requestClient.download('/mes/dv/check-record/export-excel', { params });
|
||||
return requestClient.download('/mes/dv/check-record/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,21 +20,30 @@ export namespace MesDvCheckRecordLineApi {
|
|||
|
||||
/** 查询设备点检记录明细分页 */
|
||||
export function getCheckRecordLinePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvCheckRecordLineApi.CheckRecordLine>>('/mes/dv/check-record-line/page', { params });
|
||||
return requestClient.get<PageResult<MesDvCheckRecordLineApi.CheckRecordLine>>(
|
||||
'/mes/dv/check-record-line/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备点检记录明细详情 */
|
||||
export function getCheckRecordLine(id: number) {
|
||||
return requestClient.get<MesDvCheckRecordLineApi.CheckRecordLine>(`/mes/dv/check-record-line/get?id=${id}`);
|
||||
return requestClient.get<MesDvCheckRecordLineApi.CheckRecordLine>(
|
||||
`/mes/dv/check-record-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增设备点检记录明细 */
|
||||
export function createCheckRecordLine(data: MesDvCheckRecordLineApi.CheckRecordLine) {
|
||||
export function createCheckRecordLine(
|
||||
data: MesDvCheckRecordLineApi.CheckRecordLine,
|
||||
) {
|
||||
return requestClient.post('/mes/dv/check-record-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改设备点检记录明细 */
|
||||
export function updateCheckRecordLine(data: MesDvCheckRecordLineApi.CheckRecordLine) {
|
||||
export function updateCheckRecordLine(
|
||||
data: MesDvCheckRecordLineApi.CheckRecordLine,
|
||||
) {
|
||||
return requestClient.put('/mes/dv/check-record-line/update', data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,17 +31,24 @@ export namespace MesDvMachineryApi {
|
|||
|
||||
/** 查询设备分页 */
|
||||
export function getMachineryPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvMachineryApi.Machinery>>('/mes/dv/machinery/page', { params });
|
||||
return requestClient.get<PageResult<MesDvMachineryApi.Machinery>>(
|
||||
'/mes/dv/machinery/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备精简列表 */
|
||||
export function getMachinerySimpleList() {
|
||||
return requestClient.get<MesDvMachineryApi.Machinery[]>('/mes/dv/machinery/simple-list');
|
||||
return requestClient.get<MesDvMachineryApi.Machinery[]>(
|
||||
'/mes/dv/machinery/simple-list',
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备详情 */
|
||||
export function getMachinery(id: number) {
|
||||
return requestClient.get<MesDvMachineryApi.Machinery>(`/mes/dv/machinery/get?id=${id}`);
|
||||
return requestClient.get<MesDvMachineryApi.Machinery>(
|
||||
`/mes/dv/machinery/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增设备 */
|
||||
|
|
@ -72,7 +79,7 @@ export function importMachineryTemplate() {
|
|||
/** 导入设备 */
|
||||
export function importMachinery(file: File, updateSupport: boolean) {
|
||||
return requestClient.upload<MesDvMachineryApi.MachineryImportRespVO>(
|
||||
'/mes/dv/machinery/import?updateSupport=' + updateSupport,
|
||||
`/mes/dv/machinery/import?updateSupport=${updateSupport}`,
|
||||
{ file },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,17 +17,24 @@ export namespace MesDvMachineryTypeApi {
|
|||
|
||||
/** 查询设备类型列表 */
|
||||
export function getMachineryTypeList(params?: any) {
|
||||
return requestClient.get<MesDvMachineryTypeApi.MachineryType[]>('/mes/dv/machinery-type/list', { params });
|
||||
return requestClient.get<MesDvMachineryTypeApi.MachineryType[]>(
|
||||
'/mes/dv/machinery-type/list',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备类型精简列表 */
|
||||
export function getMachineryTypeSimpleList() {
|
||||
return requestClient.get<MesDvMachineryTypeApi.MachineryType[]>('/mes/dv/machinery-type/simple-list');
|
||||
return requestClient.get<MesDvMachineryTypeApi.MachineryType[]>(
|
||||
'/mes/dv/machinery-type/simple-list',
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备类型详情 */
|
||||
export function getMachineryType(id: number) {
|
||||
return requestClient.get<MesDvMachineryTypeApi.MachineryType>(`/mes/dv/machinery-type/get?id=${id}`);
|
||||
return requestClient.get<MesDvMachineryTypeApi.MachineryType>(
|
||||
`/mes/dv/machinery-type/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增设备类型 */
|
||||
|
|
|
|||
|
|
@ -24,12 +24,17 @@ export namespace MesDvMaintenRecordApi {
|
|||
|
||||
/** 查询设备保养记录分页 */
|
||||
export function getMaintenRecordPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvMaintenRecordApi.MaintenRecord>>('/mes/dv/mainten-record/page', { params });
|
||||
return requestClient.get<PageResult<MesDvMaintenRecordApi.MaintenRecord>>(
|
||||
'/mes/dv/mainten-record/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询设备保养记录详情 */
|
||||
export function getMaintenRecord(id: number) {
|
||||
return requestClient.get<MesDvMaintenRecordApi.MaintenRecord>(`/mes/dv/mainten-record/get?id=${id}`);
|
||||
return requestClient.get<MesDvMaintenRecordApi.MaintenRecord>(
|
||||
`/mes/dv/mainten-record/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增设备保养记录 */
|
||||
|
|
@ -54,5 +59,7 @@ export function deleteMaintenRecord(id: number) {
|
|||
|
||||
/** 导出设备保养记录 */
|
||||
export function exportMaintenRecord(params: any) {
|
||||
return requestClient.download('/mes/dv/mainten-record/export-excel', { params });
|
||||
return requestClient.download('/mes/dv/mainten-record/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,29 @@ export namespace MesDvMaintenRecordLineApi {
|
|||
|
||||
/** 查询设备保养记录明细分页 */
|
||||
export function getMaintenRecordLinePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvMaintenRecordLineApi.MaintenRecordLine>>('/mes/dv/mainten-record-line/page', { params });
|
||||
return requestClient.get<
|
||||
PageResult<MesDvMaintenRecordLineApi.MaintenRecordLine>
|
||||
>('/mes/dv/mainten-record-line/page', { params });
|
||||
}
|
||||
|
||||
/** 查询设备保养记录明细详情 */
|
||||
export function getMaintenRecordLine(id: number) {
|
||||
return requestClient.get<MesDvMaintenRecordLineApi.MaintenRecordLine>(`/mes/dv/mainten-record-line/get?id=${id}`);
|
||||
return requestClient.get<MesDvMaintenRecordLineApi.MaintenRecordLine>(
|
||||
`/mes/dv/mainten-record-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增设备保养记录明细 */
|
||||
export function createMaintenRecordLine(data: MesDvMaintenRecordLineApi.MaintenRecordLine) {
|
||||
export function createMaintenRecordLine(
|
||||
data: MesDvMaintenRecordLineApi.MaintenRecordLine,
|
||||
) {
|
||||
return requestClient.post('/mes/dv/mainten-record-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改设备保养记录明细 */
|
||||
export function updateMaintenRecordLine(data: MesDvMaintenRecordLineApi.MaintenRecordLine) {
|
||||
export function updateMaintenRecordLine(
|
||||
data: MesDvMaintenRecordLineApi.MaintenRecordLine,
|
||||
) {
|
||||
return requestClient.put('/mes/dv/mainten-record-line/update', data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,12 +32,17 @@ export namespace MesDvRepairApi {
|
|||
|
||||
/** 查询维修工单分页 */
|
||||
export function getRepairPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvRepairApi.Repair>>('/mes/dv/repair/page', { params });
|
||||
return requestClient.get<PageResult<MesDvRepairApi.Repair>>(
|
||||
'/mes/dv/repair/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询维修工单详情 */
|
||||
export function getRepair(id: number) {
|
||||
return requestClient.get<MesDvRepairApi.Repair>(`/mes/dv/repair/get?id=${id}`);
|
||||
return requestClient.get<MesDvRepairApi.Repair>(
|
||||
`/mes/dv/repair/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增维修工单 */
|
||||
|
|
|
|||
|
|
@ -20,12 +20,17 @@ export namespace MesDvRepairLineApi {
|
|||
|
||||
/** 查询维修工单行分页 */
|
||||
export function getRepairLinePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvRepairLineApi.RepairLine>>('/mes/dv/repair-line/page', { params });
|
||||
return requestClient.get<PageResult<MesDvRepairLineApi.RepairLine>>(
|
||||
'/mes/dv/repair-line/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询维修工单行详情 */
|
||||
export function getRepairLine(id: number) {
|
||||
return requestClient.get<MesDvRepairLineApi.RepairLine>(`/mes/dv/repair-line/get?id=${id}`);
|
||||
return requestClient.get<MesDvRepairLineApi.RepairLine>(
|
||||
`/mes/dv/repair-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增维修工单行 */
|
||||
|
|
|
|||
|
|
@ -19,17 +19,24 @@ export namespace MesDvSubjectApi {
|
|||
|
||||
/** 查询点检保养项目分页 */
|
||||
export function getSubjectPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesDvSubjectApi.Subject>>('/mes/dv/subject/page', { params });
|
||||
return requestClient.get<PageResult<MesDvSubjectApi.Subject>>(
|
||||
'/mes/dv/subject/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询点检保养项目精简列表 */
|
||||
export function getSubjectSimpleList() {
|
||||
return requestClient.get<MesDvSubjectApi.Subject[]>('/mes/dv/subject/simple-list');
|
||||
return requestClient.get<MesDvSubjectApi.Subject[]>(
|
||||
'/mes/dv/subject/simple-list',
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询点检保养项目详情 */
|
||||
export function getSubject(id: number) {
|
||||
return requestClient.get<MesDvSubjectApi.Subject>(`/mes/dv/subject/get?id=${id}`);
|
||||
return requestClient.get<MesDvSubjectApi.Subject>(
|
||||
`/mes/dv/subject/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增点检保养项目 */
|
||||
|
|
|
|||
|
|
@ -34,16 +34,12 @@ export function getAutoCodePartListByRuleId(ruleId: number) {
|
|||
}
|
||||
|
||||
/** 新增编码规则分段 */
|
||||
export function createAutoCodePart(
|
||||
data: MesMdAutoCodePartApi.AutoCodePart,
|
||||
) {
|
||||
export function createAutoCodePart(data: MesMdAutoCodePartApi.AutoCodePart) {
|
||||
return requestClient.post('/mes/md/auto-code-part/create', data);
|
||||
}
|
||||
|
||||
/** 修改编码规则分段 */
|
||||
export function updateAutoCodePart(
|
||||
data: MesMdAutoCodePartApi.AutoCodePart,
|
||||
) {
|
||||
export function updateAutoCodePart(data: MesMdAutoCodePartApi.AutoCodePart) {
|
||||
return requestClient.put('/mes/md/auto-code-part/update', data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ export namespace MesMdAutoCodeRuleApi {
|
|||
|
||||
/** 查询编码规则分页 */
|
||||
export function getAutoCodeRulePage(params: PageParam) {
|
||||
return requestClient.get<
|
||||
PageResult<MesMdAutoCodeRuleApi.AutoCodeRule>
|
||||
>('/mes/md/auto-code-rule/page', { params });
|
||||
return requestClient.get<PageResult<MesMdAutoCodeRuleApi.AutoCodeRule>>(
|
||||
'/mes/md/auto-code-rule/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询编码规则详情 */
|
||||
|
|
@ -34,16 +35,12 @@ export function getAutoCodeRule(id: number) {
|
|||
}
|
||||
|
||||
/** 新增编码规则 */
|
||||
export function createAutoCodeRule(
|
||||
data: MesMdAutoCodeRuleApi.AutoCodeRule,
|
||||
) {
|
||||
export function createAutoCodeRule(data: MesMdAutoCodeRuleApi.AutoCodeRule) {
|
||||
return requestClient.post('/mes/md/auto-code-rule/create', data);
|
||||
}
|
||||
|
||||
/** 修改编码规则 */
|
||||
export function updateAutoCodeRule(
|
||||
data: MesMdAutoCodeRuleApi.AutoCodeRule,
|
||||
) {
|
||||
export function updateAutoCodeRule(data: MesMdAutoCodeRuleApi.AutoCodeRule) {
|
||||
return requestClient.put('/mes/md/auto-code-rule/update', data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ export function getBatchConfigByItemId(itemId: number) {
|
|||
}
|
||||
|
||||
/** 保存批次属性配置 */
|
||||
export function saveBatchConfig(
|
||||
data: MesMdItemBatchConfigApi.BatchConfig,
|
||||
) {
|
||||
export function saveBatchConfig(data: MesMdItemBatchConfigApi.BatchConfig) {
|
||||
return requestClient.post('/mes/md/item-batch-config/save', data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,5 +56,7 @@ export function deleteUnitMeasure(id: number) {
|
|||
|
||||
/** 导出计量单位 */
|
||||
export function exportUnitMeasure(params: PageParam) {
|
||||
return requestClient.download('/mes/md/unit-measure/export-excel', { params });
|
||||
return requestClient.download('/mes/md/unit-measure/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ export namespace MesTmToolApi {
|
|||
|
||||
/** 查询工具台账分页 */
|
||||
export function getToolPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesTmToolApi.Tool>>('/mes/tm/tool/page', { params });
|
||||
return requestClient.get<PageResult<MesTmToolApi.Tool>>('/mes/tm/tool/page', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/** 查询工具精简列表 */
|
||||
|
|
|
|||
|
|
@ -18,17 +18,24 @@ export namespace MesTmToolTypeApi {
|
|||
|
||||
/** 查询工具类型分页 */
|
||||
export function getToolTypePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesTmToolTypeApi.ToolType>>('/mes/tm/tool-type/page', { params });
|
||||
return requestClient.get<PageResult<MesTmToolTypeApi.ToolType>>(
|
||||
'/mes/tm/tool-type/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询工具类型精简列表 */
|
||||
export function getToolTypeSimpleList() {
|
||||
return requestClient.get<MesTmToolTypeApi.ToolType[]>('/mes/tm/tool-type/simple-list');
|
||||
return requestClient.get<MesTmToolTypeApi.ToolType[]>(
|
||||
'/mes/tm/tool-type/simple-list',
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询工具类型详情 */
|
||||
export function getToolType(id: number) {
|
||||
return requestClient.get<MesTmToolTypeApi.ToolType>(`/mes/tm/tool-type/get?id=${id}`);
|
||||
return requestClient.get<MesTmToolTypeApi.ToolType>(
|
||||
`/mes/tm/tool-type/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增工具类型 */
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import {
|
|||
TenantDropdown,
|
||||
UserDropdown,
|
||||
} from '@vben/layouts';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { preferences, usePreferences } from '@vben/preferences';
|
||||
import { useAccessStore, useUserStore } from '@vben/stores';
|
||||
import { formatDateTime, openWindow } from '@vben/utils';
|
||||
|
||||
|
|
@ -55,6 +55,7 @@ const showDot = computed(() => unreadCount.value > 0);
|
|||
const [HelpModal, helpModalApi] = useVbenModal({
|
||||
connectedComponent: Help,
|
||||
});
|
||||
const { isDark } = usePreferences();
|
||||
|
||||
const menus = computed(() => [
|
||||
{
|
||||
|
|
@ -201,14 +202,57 @@ onMounted(() => {
|
|||
);
|
||||
});
|
||||
|
||||
const handleClick = (item: NotificationItem) => {
|
||||
// 如果通知项有链接,点击时跳转
|
||||
if (item.link) {
|
||||
navigateTo(item.link, item.query, item.state);
|
||||
}
|
||||
};
|
||||
|
||||
function navigateTo(
|
||||
link: string,
|
||||
query?: Record<string, any>,
|
||||
state?: Record<string, any>,
|
||||
) {
|
||||
if (link.startsWith('http://') || link.startsWith('https://')) {
|
||||
// 外部链接,在新标签页打开
|
||||
window.open(link, '_blank');
|
||||
} else {
|
||||
// 内部路由链接,支持 query 参数和 state
|
||||
router.push({
|
||||
path: link,
|
||||
query: query || {},
|
||||
state,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => ({
|
||||
enable: preferences.app.watermark,
|
||||
content: preferences.app.watermarkContent,
|
||||
isDark: isDark.value,
|
||||
}),
|
||||
async ({ enable, content }) => {
|
||||
async ({ enable, content, isDark: isDarkValue }) => {
|
||||
if (enable) {
|
||||
const watermarkColor = isDarkValue
|
||||
? 'rgba(255, 255, 255, 0.12)'
|
||||
: 'rgba(0, 0, 0, 0.12)';
|
||||
|
||||
await updateWatermark({
|
||||
advancedStyle: {
|
||||
colorStops: [
|
||||
{
|
||||
color: watermarkColor,
|
||||
offset: 0,
|
||||
},
|
||||
{
|
||||
color: watermarkColor,
|
||||
offset: 1,
|
||||
},
|
||||
],
|
||||
type: 'linear',
|
||||
},
|
||||
content:
|
||||
content ||
|
||||
`${userStore.userInfo?.id} - ${userStore.userInfo?.nickname}`,
|
||||
|
|
@ -233,6 +277,7 @@ watch(
|
|||
:description="userStore.userInfo?.email"
|
||||
:tag-text="userStore.userInfo?.username"
|
||||
@logout="handleLogout"
|
||||
@clear-preferences-and-logout="handleLogout"
|
||||
/>
|
||||
</template>
|
||||
<template #notification>
|
||||
|
|
@ -244,6 +289,7 @@ watch(
|
|||
@view-all="handleNotificationViewAll"
|
||||
@open="handleNotificationOpen"
|
||||
@read="handleNotificationRead"
|
||||
@on-click="handleClick"
|
||||
/>
|
||||
</template>
|
||||
<template #header-right-1>
|
||||
|
|
|
|||
|
|
@ -36,8 +36,7 @@ const routes: RouteRecordRaw[] = [
|
|||
title: '固件详情',
|
||||
activePath: '/iot/ota',
|
||||
},
|
||||
component: () =>
|
||||
import('#/views/iot/ota/firmware/detail/index.vue'),
|
||||
component: () => import('#/views/iot/ota/firmware/detail/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -126,8 +126,7 @@ export function useGridColumns(): VxeTableGridOptions<AlertRecordApi.AlertRecord
|
|||
title: '设备名称',
|
||||
minWidth: 120,
|
||||
formatter: ({ cellValue }) =>
|
||||
deviceList.find((device) => device.id === cellValue)?.deviceName ||
|
||||
'-',
|
||||
deviceList.find((device) => device.id === cellValue)?.deviceName || '-',
|
||||
},
|
||||
{
|
||||
field: 'deviceMessage',
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ function handleProcess(row: AlertRecordApi.AlertRecord) {
|
|||
h('div', { class: 'space-y-2' }, [
|
||||
h('p', '请输入处理原因:'),
|
||||
h(Input.TextArea, {
|
||||
'value': processRemark.value,
|
||||
value: processRemark.value,
|
||||
'onUpdate:value': (val: string) => (processRemark.value = val),
|
||||
'rows': 3,
|
||||
'placeholder': '请输入处理原因',
|
||||
rows: 3,
|
||||
placeholder: '请输入处理原因',
|
||||
}),
|
||||
]),
|
||||
async onOk() {
|
||||
|
|
@ -106,7 +106,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
:overlay-style="{ maxWidth: '600px' }"
|
||||
>
|
||||
<template #content>
|
||||
<pre class="text-xs">{{ stringifyDeviceMessage(row.deviceMessage) }}</pre>
|
||||
<pre class="text-xs">{{
|
||||
stringifyDeviceMessage(row.deviceMessage)
|
||||
}}</pre>
|
||||
</template>
|
||||
<Button size="small" type="link">
|
||||
<IconifyIcon icon="ant-design:eye-outlined" class="mr-1" />
|
||||
|
|
|
|||
|
|
@ -206,9 +206,7 @@ onMounted(() => {
|
|||
</div>
|
||||
</div>
|
||||
<!-- 按钮组 -->
|
||||
<div
|
||||
class="mt-auto flex gap-2 border-t border-border pt-3"
|
||||
>
|
||||
<div class="mt-auto flex gap-2 border-t border-border pt-3">
|
||||
<Button
|
||||
v-if="hasAccessByCodes(['iot:device:update'])"
|
||||
size="small"
|
||||
|
|
|
|||
|
|
@ -134,7 +134,9 @@ const [Modal, modalApi] = useVbenModal({
|
|||
advValues.latitude !== null &&
|
||||
advValues.latitude !== '';
|
||||
if (hasLongitude !== hasLatitude) {
|
||||
message.warning(hasLongitude ? '请同时填写设备纬度' : '请同时填写设备经度');
|
||||
message.warning(
|
||||
hasLongitude ? '请同时填写设备纬度' : '请同时填写设备经度',
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ async function renderChartWhenReady() {
|
|||
await nextTick();
|
||||
initChart();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ export function getProductName(productId?: number): string {
|
|||
if (!productId) {
|
||||
return '-';
|
||||
}
|
||||
return (
|
||||
productList.find((product) => product.id === productId)?.name || '-'
|
||||
);
|
||||
return productList.find((product) => product.id === productId)?.name || '-';
|
||||
}
|
||||
|
||||
/** 固件详情的描述字段 */
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
taskId: props.taskId,
|
||||
status: activeTab.value === '' ? undefined : Number(activeTab.value),
|
||||
status:
|
||||
activeTab.value === '' ? undefined : Number(activeTab.value),
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
@ -97,16 +98,8 @@ watch(
|
|||
|
||||
<template>
|
||||
<Card title="升级设备记录">
|
||||
<Tabs
|
||||
v-model:active-key="activeTab"
|
||||
@change="handleTabChange"
|
||||
class="mb-4"
|
||||
>
|
||||
<Tabs.TabPane
|
||||
v-for="tab in statusTabs"
|
||||
:key="tab.key"
|
||||
:tab="tab.label"
|
||||
/>
|
||||
<Tabs v-model:active-key="activeTab" @change="handleTabChange" class="mb-4">
|
||||
<Tabs.TabPane v-for="tab in statusTabs" :key="tab.key" :tab="tab.label" />
|
||||
</Tabs>
|
||||
<Grid>
|
||||
<template #actions="{ row }">
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ async function copyToClipboard(text: string) {
|
|||
</Descriptions.Item>
|
||||
<Descriptions.Item
|
||||
v-if="
|
||||
([DeviceTypeEnum.DEVICE, DeviceTypeEnum.GATEWAY] as number[]).includes(
|
||||
product.deviceType!,
|
||||
)
|
||||
(
|
||||
[DeviceTypeEnum.DEVICE, DeviceTypeEnum.GATEWAY] as number[]
|
||||
).includes(product.deviceType!)
|
||||
"
|
||||
label="联网方式"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -182,9 +182,7 @@ onMounted(() => {
|
|||
</div>
|
||||
</div>
|
||||
<!-- 按钮组 -->
|
||||
<div
|
||||
class="mt-auto flex gap-2 border-t border-border pt-3"
|
||||
>
|
||||
<div class="mt-auto flex gap-2 border-t border-border pt-3">
|
||||
<Button
|
||||
v-if="hasAccessByCodes(['iot:product:update'])"
|
||||
size="small"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||
|
||||
import { IotDeviceMessageMethodEnum, IoTThingModelTypeEnum } from '@vben/constants';
|
||||
import {
|
||||
IotDeviceMessageMethodEnum,
|
||||
IoTThingModelTypeEnum,
|
||||
} from '@vben/constants';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Button, message, Select } from 'ant-design-vue';
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ onMounted(() => {
|
|||
<template>
|
||||
<Form.Item
|
||||
:name="['config', 'jdbcUrl']"
|
||||
:rules="[{ required: true, message: 'JDBC 连接地址不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: 'JDBC 连接地址不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="JDBC 地址"
|
||||
>
|
||||
<Input
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<!--suppress HttpUrlsUsage -->
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -67,7 +66,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'method']"
|
||||
:rules="[{ required: true, message: '请求方法不能为空', trigger: 'change' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '请求方法不能为空', trigger: 'change' },
|
||||
]"
|
||||
label="请求方法"
|
||||
>
|
||||
<Select v-model:value="config.method" placeholder="请选择请求方法">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -55,7 +54,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'clientId']"
|
||||
:rules="[{ required: true, message: '客户端 ID 不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '客户端 ID 不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="客户端 ID"
|
||||
>
|
||||
<Input v-model:value="config.clientId" placeholder="请输入客户端 ID" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -37,7 +36,10 @@ onMounted(() => {
|
|||
:rules="[{ required: true, message: '主机地址不能为空', trigger: 'blur' }]"
|
||||
label="主机地址"
|
||||
>
|
||||
<Input v-model:value="config.host" placeholder="请输入主机地址,如:localhost" />
|
||||
<Input
|
||||
v-model:value="config.host"
|
||||
placeholder="请输入主机地址,如:localhost"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'port']"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -34,7 +33,10 @@ onMounted(() => {
|
|||
:rules="[{ required: true, message: '主机地址不能为空', trigger: 'blur' }]"
|
||||
label="主机地址"
|
||||
>
|
||||
<Input v-model:value="config.host" placeholder="请输入主机地址,如:localhost" />
|
||||
<Input
|
||||
v-model:value="config.host"
|
||||
placeholder="请输入主机地址,如:localhost"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'port']"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -32,7 +31,9 @@ onMounted(() => {
|
|||
<template>
|
||||
<Form.Item
|
||||
:name="['config', 'nameServer']"
|
||||
:rules="[{ required: true, message: 'NameServer 地址不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: 'NameServer 地址不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="NameServer"
|
||||
>
|
||||
<Input
|
||||
|
|
@ -42,14 +43,18 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'accessKey']"
|
||||
:rules="[{ required: true, message: 'AccessKey 不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: 'AccessKey 不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="AccessKey"
|
||||
>
|
||||
<Input v-model:value="config.accessKey" placeholder="请输入 AccessKey" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'secretKey']"
|
||||
:rules="[{ required: true, message: 'SecretKey 不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: 'SecretKey 不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="SecretKey"
|
||||
>
|
||||
<Input.Password
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -68,7 +67,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'connectTimeoutMs']"
|
||||
:rules="[{ required: true, message: '连接超时时间不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '连接超时时间不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="连接超时(ms)"
|
||||
>
|
||||
<InputNumber
|
||||
|
|
@ -80,7 +81,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'readTimeoutMs']"
|
||||
:rules="[{ required: true, message: '读取超时时间不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '读取超时时间不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="读取超时(ms)"
|
||||
>
|
||||
<InputNumber
|
||||
|
|
@ -98,11 +101,16 @@ onMounted(() => {
|
|||
:name="['config', 'sslCertPath']"
|
||||
label="SSL 证书路径"
|
||||
>
|
||||
<Input v-model:value="config.sslCertPath" placeholder="请输入 SSL 证书路径" />
|
||||
<Input
|
||||
v-model:value="config.sslCertPath"
|
||||
placeholder="请输入 SSL 证书路径"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'dataFormat']"
|
||||
:rules="[{ required: true, message: '数据格式不能为空', trigger: 'change' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '数据格式不能为空', trigger: 'change' },
|
||||
]"
|
||||
label="数据格式"
|
||||
>
|
||||
<Select v-model:value="config.dataFormat" placeholder="请选择数据格式">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { isEmpty } from '@vben/utils';
|
||||
|
|
@ -41,7 +40,11 @@ onMounted(() => {
|
|||
<Form.Item
|
||||
:name="['config', 'serverUrl']"
|
||||
:rules="[
|
||||
{ required: true, message: 'WebSocket 服务器地址不能为空', trigger: 'blur' },
|
||||
{
|
||||
required: true,
|
||||
message: 'WebSocket 服务器地址不能为空',
|
||||
trigger: 'blur',
|
||||
},
|
||||
]"
|
||||
label="服务器地址"
|
||||
>
|
||||
|
|
@ -52,7 +55,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'connectTimeoutMs']"
|
||||
:rules="[{ required: true, message: '连接超时时间不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '连接超时时间不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="连接超时(ms)"
|
||||
>
|
||||
<InputNumber
|
||||
|
|
@ -64,7 +69,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'sendTimeoutMs']"
|
||||
:rules="[{ required: true, message: '发送超时时间不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '发送超时时间不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="发送超时(ms)"
|
||||
>
|
||||
<InputNumber
|
||||
|
|
@ -107,7 +114,9 @@ onMounted(() => {
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
:name="['config', 'dataFormat']"
|
||||
:rules="[{ required: true, message: '数据格式不能为空', trigger: 'change' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '数据格式不能为空', trigger: 'change' },
|
||||
]"
|
||||
label="数据格式"
|
||||
>
|
||||
<Select v-model:value="config.dataFormat" placeholder="请选择数据格式">
|
||||
|
|
|
|||
|
|
@ -103,7 +103,9 @@ function handleTypeChange(type: number) {
|
|||
class="mx-4"
|
||||
>
|
||||
<Form.Item
|
||||
:rules="[{ required: true, message: '目的名称不能为空', trigger: 'blur' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '目的名称不能为空', trigger: 'blur' },
|
||||
]"
|
||||
label="目的名称"
|
||||
name="name"
|
||||
>
|
||||
|
|
@ -117,13 +119,17 @@ function handleTypeChange(type: number) {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
:rules="[{ required: true, message: '目的类型不能为空', trigger: 'change' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '目的类型不能为空', trigger: 'change' },
|
||||
]"
|
||||
label="目的类型"
|
||||
name="type"
|
||||
>
|
||||
<Select
|
||||
:value="formData.type"
|
||||
:options="getDictOptions(DICT_TYPE.IOT_DATA_SINK_TYPE_ENUM, 'number') as any"
|
||||
:options="
|
||||
getDictOptions(DICT_TYPE.IOT_DATA_SINK_TYPE_ENUM, 'number') as any
|
||||
"
|
||||
placeholder="请选择目的类型"
|
||||
@change="(value: any) => handleTypeChange(value as number)"
|
||||
/>
|
||||
|
|
@ -166,7 +172,9 @@ function handleTypeChange(type: number) {
|
|||
v-model="formData.config"
|
||||
/>
|
||||
<Form.Item
|
||||
:rules="[{ required: true, message: '目的状态不能为空', trigger: 'change' }]"
|
||||
:rules="[
|
||||
{ required: true, message: '目的状态不能为空', trigger: 'change' },
|
||||
]"
|
||||
label="目的状态"
|
||||
name="status"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -108,9 +108,8 @@ function handleDeviceChange(deviceId?: number) {
|
|||
function handleServiceChange(serviceIdentifier?: any) {
|
||||
// 根据服务标识符找到对应的服务对象
|
||||
const service =
|
||||
serviceList.value.find(
|
||||
(item) => item.identifier === serviceIdentifier,
|
||||
) || null;
|
||||
serviceList.value.find((item) => item.identifier === serviceIdentifier) ||
|
||||
null;
|
||||
selectedService.value = service;
|
||||
|
||||
// 当服务变化时,清空参数配置
|
||||
|
|
|
|||
|
|
@ -240,15 +240,23 @@ function removeConditionGroup() {
|
|||
>
|
||||
<div class="gap-[8px] flex items-center">
|
||||
<!-- 连接线 -->
|
||||
<div class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"></div>
|
||||
<div
|
||||
class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"
|
||||
></div>
|
||||
<!-- 或标签 -->
|
||||
<div
|
||||
class="px-[14px] py-[3px] rounded-full border border-orange-300 bg-orange-100 dark:border-orange-800 dark:bg-orange-950/50"
|
||||
>
|
||||
<span class="text-[13px] font-semibold text-orange-600 dark:text-orange-300">或</span>
|
||||
<span
|
||||
class="text-[13px] font-semibold text-orange-600 dark:text-orange-300"
|
||||
>
|
||||
或
|
||||
</span>
|
||||
</div>
|
||||
<!-- 连接线 -->
|
||||
<div class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"></div>
|
||||
<div
|
||||
class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -261,7 +269,10 @@ function removeConditionGroup() {
|
|||
class="p-[24px] rounded-[8px] border-2 border-dashed border-orange-200 bg-orange-50/40 text-center dark:border-orange-900/40 dark:bg-orange-950/10"
|
||||
>
|
||||
<div class="gap-[10px] flex flex-col items-center">
|
||||
<IconifyIcon icon="lucide:plus" class="text-[28px] text-orange-400 dark:text-orange-300" />
|
||||
<IconifyIcon
|
||||
icon="lucide:plus"
|
||||
class="text-[28px] text-orange-400 dark:text-orange-300"
|
||||
/>
|
||||
<div class="text-orange-600 dark:text-orange-300">
|
||||
<p class="text-[13px] font-medium mb-[2px]">暂无子条件组</p>
|
||||
<p class="text-[12px]">点击上方「添加子条件组」按钮开始配置</p>
|
||||
|
|
|
|||
|
|
@ -159,7 +159,9 @@ function updateConditionGroup(
|
|||
>
|
||||
<span
|
||||
class="text-[13px] font-semibold text-orange-600 dark:text-orange-300"
|
||||
>或</span>
|
||||
>
|
||||
或
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"
|
||||
|
|
|
|||
|
|
@ -436,79 +436,75 @@ watch(
|
|||
<template #content>
|
||||
<!-- 弹出层内容 -->
|
||||
<div class="json-params-detail-content">
|
||||
<div class="mb-4 flex items-center gap-2">
|
||||
<IconifyIcon :icon="titleIcon" class="text-lg text-primary" />
|
||||
<span class="text-base font-bold text-foreground">
|
||||
{{ title }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-4 flex items-center gap-2">
|
||||
<IconifyIcon :icon="titleIcon" class="text-lg text-primary" />
|
||||
<span class="text-base font-bold text-foreground">
|
||||
{{ title }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- 参数列表 -->
|
||||
<div v-if="paramsList.length > 0">
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<IconifyIcon
|
||||
:icon="paramsIcon"
|
||||
class="text-base text-primary"
|
||||
/>
|
||||
<span class="text-base font-bold text-foreground">
|
||||
{{ paramsLabel }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="ml-6 space-y-2">
|
||||
<div
|
||||
v-for="param in paramsList"
|
||||
:key="param.identifier"
|
||||
class="flex items-center justify-between rounded-lg bg-card p-2"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<div class="text-base font-bold text-foreground">
|
||||
{{ param.name }}
|
||||
<Tag
|
||||
v-if="param.required"
|
||||
color="error"
|
||||
class="ml-1"
|
||||
>
|
||||
{{ JSON_PARAMS_INPUT_CONSTANTS.REQUIRED_TAG }}
|
||||
<div class="space-y-4">
|
||||
<!-- 参数列表 -->
|
||||
<div v-if="paramsList.length > 0">
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<IconifyIcon
|
||||
:icon="paramsIcon"
|
||||
class="text-base text-primary"
|
||||
/>
|
||||
<span class="text-base font-bold text-foreground">
|
||||
{{ paramsLabel }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="ml-6 space-y-2">
|
||||
<div
|
||||
v-for="param in paramsList"
|
||||
:key="param.identifier"
|
||||
class="flex items-center justify-between rounded-lg bg-card p-2"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<div class="text-base font-bold text-foreground">
|
||||
{{ param.name }}
|
||||
<Tag v-if="param.required" color="error" class="ml-1">
|
||||
{{ JSON_PARAMS_INPUT_CONSTANTS.REQUIRED_TAG }}
|
||||
</Tag>
|
||||
</div>
|
||||
<div class="text-xs text-muted-foreground">
|
||||
{{ param.identifier }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Tag :color="getParamTypeTag(param.dataType)">
|
||||
{{ getParamTypeName(param.dataType) }}
|
||||
</Tag>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
{{ getExampleValue(param) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-xs text-muted-foreground">
|
||||
{{ param.identifier }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Tag :color="getParamTypeTag(param.dataType)">
|
||||
{{ getParamTypeName(param.dataType) }}
|
||||
</Tag>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
{{ getExampleValue(param) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-6 mt-3">
|
||||
<div class="mb-1 text-xs text-muted-foreground">
|
||||
{{ JSON_PARAMS_INPUT_CONSTANTS.COMPLETE_JSON_FORMAT }}
|
||||
</div>
|
||||
<pre
|
||||
class="border-l-[3px] overflow-x-auto rounded-lg border-primary bg-card p-3 text-sm text-foreground"
|
||||
>
|
||||
<div class="ml-6 mt-3">
|
||||
<div class="mb-1 text-xs text-muted-foreground">
|
||||
{{ JSON_PARAMS_INPUT_CONSTANTS.COMPLETE_JSON_FORMAT }}
|
||||
</div>
|
||||
<pre
|
||||
class="border-l-[3px] overflow-x-auto rounded-lg border-primary bg-card p-3 text-sm text-foreground"
|
||||
>
|
||||
<code>{{ generateExampleJson() }}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 无参数提示 -->
|
||||
<div v-else>
|
||||
<div class="py-4 text-center">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ emptyMessage }}
|
||||
</p>
|
||||
<!-- 无参数提示 -->
|
||||
<div v-else>
|
||||
<div class="py-4 text-center">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ emptyMessage }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<Button
|
||||
type="link"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,14 @@ import {
|
|||
} from '@vben/constants';
|
||||
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { DatePicker, Input, InputNumber, Select, Tag, Tooltip } from 'ant-design-vue';
|
||||
import {
|
||||
DatePicker,
|
||||
Input,
|
||||
InputNumber,
|
||||
Select,
|
||||
Tag,
|
||||
Tooltip,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
/** 值输入组件 */
|
||||
defineOptions({ name: 'ValueInput' });
|
||||
|
|
@ -134,7 +141,7 @@ function handleDateChange(value: any) {
|
|||
|
||||
/** 处理数字变化事件 ;InputNumber 回调值类型为 ValueType(string | number) */
|
||||
function handleNumberChange(value: any) {
|
||||
localValue.value = value == null ? '' : String(value);
|
||||
localValue.value = value === null ? '' : String(value);
|
||||
}
|
||||
|
||||
/** 监听操作符变化 */
|
||||
|
|
@ -233,11 +240,7 @@ watch(
|
|||
class="mt-2 flex flex-wrap items-center gap-1"
|
||||
>
|
||||
<span class="text-xs text-muted-foreground"> 解析结果: </span>
|
||||
<Tag
|
||||
v-for="(item, index) in listPreview"
|
||||
:key="index"
|
||||
class="m-0"
|
||||
>
|
||||
<Tag v-for="(item, index) in listPreview" :key="index" class="m-0">
|
||||
{{ item }}
|
||||
</Tag>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -268,7 +268,9 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
|||
>
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<IconifyIcon icon="ep:warning" class="text-base text-warning" />
|
||||
<span class="font-semibold text-sm text-foreground">触发告警</span>
|
||||
<span class="font-semibold text-sm text-foreground">
|
||||
触发告警
|
||||
</span>
|
||||
<Tag color="warning">自动执行</Tag>
|
||||
</div>
|
||||
<div class="text-xs leading-relaxed text-muted-foreground">
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ const formData = useVModel(props, 'modelValue', emit); // 表单数据
|
|||
<div class="flex items-center justify-between">
|
||||
<div class="gap-[8px] flex items-center">
|
||||
<IconifyIcon icon="ep:info-filled" class="text-[18px] text-primary" />
|
||||
<span class="text-[16px] font-semibold text-foreground">基础信息</span>
|
||||
<span class="text-[16px] font-semibold text-foreground">
|
||||
基础信息
|
||||
</span>
|
||||
</div>
|
||||
<div class="gap-[8px] flex items-center">
|
||||
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="formData.status" />
|
||||
|
|
|
|||
|
|
@ -116,7 +116,9 @@ onMounted(() => {
|
|||
<div class="flex items-center justify-between">
|
||||
<div class="gap-[8px] flex items-center">
|
||||
<IconifyIcon icon="ep:lightning" class="text-[18px] text-primary" />
|
||||
<span class="text-[16px] font-semibold text-foreground">触发器配置</span>
|
||||
<span class="text-[16px] font-semibold text-foreground">
|
||||
触发器配置
|
||||
</span>
|
||||
<Tag color="default"> {{ triggers.length }} 个触发器 </Tag>
|
||||
</div>
|
||||
<Button type="primary" size="small" @click="addTrigger">
|
||||
|
|
|
|||
|
|
@ -98,9 +98,7 @@ const selectedProperty = computed(() =>
|
|||
|
||||
/** 处理选择变化事件 */
|
||||
function handleChange(value: any) {
|
||||
const property = propertyList.value.find(
|
||||
(item) => item.identifier === value,
|
||||
);
|
||||
const property = propertyList.value.find((item) => item.identifier === value);
|
||||
if (property) {
|
||||
emit('change', { type: property.dataType, config: property });
|
||||
}
|
||||
|
|
@ -154,23 +152,27 @@ function parseThingModelData(
|
|||
outputParams: event.outputParams,
|
||||
event,
|
||||
}));
|
||||
const services = (tsl.services ?? []).map<PropertySelectorItem>((service) => ({
|
||||
identifier: service.identifier!,
|
||||
name: service.name!,
|
||||
description: service.description,
|
||||
dataType: 'struct',
|
||||
type: IoTThingModelTypeEnum.SERVICE,
|
||||
callType: service.callType,
|
||||
required: service.required,
|
||||
inputParams: service.inputParams,
|
||||
outputParams: service.outputParams,
|
||||
service,
|
||||
}));
|
||||
const services = (tsl.services ?? []).map<PropertySelectorItem>(
|
||||
(service) => ({
|
||||
identifier: service.identifier!,
|
||||
name: service.name!,
|
||||
description: service.description,
|
||||
dataType: 'struct',
|
||||
type: IoTThingModelTypeEnum.SERVICE,
|
||||
callType: service.callType,
|
||||
required: service.required,
|
||||
inputParams: service.inputParams,
|
||||
outputParams: service.outputParams,
|
||||
service,
|
||||
}),
|
||||
);
|
||||
return [...properties, ...events, ...services];
|
||||
}
|
||||
|
||||
/** 获取属性取值范围:数值型给 min~max;枚举 / 布尔给选项列表 */
|
||||
function getPropertyRange(property: ThingModelApi.Property): string | undefined {
|
||||
function getPropertyRange(
|
||||
property: ThingModelApi.Property,
|
||||
): string | undefined {
|
||||
const specs = property.dataSpecs;
|
||||
if (specs && specs.min !== undefined && specs.max !== undefined) {
|
||||
return `${specs.min}~${specs.max}`;
|
||||
|
|
@ -225,7 +227,9 @@ watch(
|
|||
:value="property.identifier"
|
||||
>
|
||||
<div class="py-[2px] flex w-full items-center justify-between">
|
||||
<span class="text-[14px] font-medium flex-1 truncate text-foreground">
|
||||
<span
|
||||
class="text-[14px] font-medium flex-1 truncate text-foreground"
|
||||
>
|
||||
{{ property.name }}
|
||||
</span>
|
||||
<Tag class="ml-[8px] flex-shrink-0">
|
||||
|
|
@ -248,103 +252,125 @@ watch(
|
|||
<template #content>
|
||||
<!-- 弹出层内容 -->
|
||||
<div class="property-detail-content">
|
||||
<div class="gap-[8px] mb-[12px] flex items-center">
|
||||
<IconifyIcon icon="ep:info-filled" class="text-[16px] text-info" />
|
||||
<span class="text-[14px] font-medium text-foreground">
|
||||
{{ selectedProperty.name }}
|
||||
</span>
|
||||
<Tag>
|
||||
{{ getDataTypeName(selectedProperty.dataType) }}
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
<div class="space-y-[8px] ml-[24px]">
|
||||
<div class="gap-[8px] flex items-start">
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
标识符:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.identifier }}
|
||||
<div class="gap-[8px] mb-[12px] flex items-center">
|
||||
<IconifyIcon icon="ep:info-filled" class="text-[16px] text-info" />
|
||||
<span class="text-[14px] font-medium text-foreground">
|
||||
{{ selectedProperty.name }}
|
||||
</span>
|
||||
<Tag>
|
||||
{{ getDataTypeName(selectedProperty.dataType) }}
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="selectedProperty.description"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
描述:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.description }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="space-y-[8px] ml-[24px]">
|
||||
<div class="gap-[8px] flex items-start">
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
标识符:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.identifier }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedProperty.unit" class="gap-[8px] flex items-start">
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
单位:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.unit }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedProperty.description"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
描述:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.description }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedProperty.range" class="gap-[8px] flex items-start">
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
取值范围:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.range }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedProperty.unit"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
单位:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.unit }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 根据属性类型显示额外信息 -->
|
||||
<div
|
||||
v-if="
|
||||
selectedProperty.type === IoTThingModelTypeEnum.PROPERTY &&
|
||||
selectedProperty.accessMode
|
||||
"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
访问模式:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ getAccessModeLabel(selectedProperty.accessMode) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedProperty.range"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
取值范围:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ selectedProperty.range }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
selectedProperty.type === IoTThingModelTypeEnum.EVENT &&
|
||||
selectedProperty.eventType
|
||||
"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
事件类型:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ getEventTypeLabel(selectedProperty.eventType) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 根据属性类型显示额外信息 -->
|
||||
<div
|
||||
v-if="
|
||||
selectedProperty.type === IoTThingModelTypeEnum.PROPERTY &&
|
||||
selectedProperty.accessMode
|
||||
"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
访问模式:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ getAccessModeLabel(selectedProperty.accessMode) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
selectedProperty.type === IoTThingModelTypeEnum.SERVICE &&
|
||||
selectedProperty.callType
|
||||
"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground">
|
||||
调用类型:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ getThingModelServiceCallTypeLabel(selectedProperty.callType) }}
|
||||
</span>
|
||||
<div
|
||||
v-if="
|
||||
selectedProperty.type === IoTThingModelTypeEnum.EVENT &&
|
||||
selectedProperty.eventType
|
||||
"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
事件类型:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{ getEventTypeLabel(selectedProperty.eventType) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
selectedProperty.type === IoTThingModelTypeEnum.SERVICE &&
|
||||
selectedProperty.callType
|
||||
"
|
||||
class="gap-[8px] flex items-start"
|
||||
>
|
||||
<span
|
||||
class="text-[12px] min-w-[60px] flex-shrink-0 text-muted-foreground"
|
||||
>
|
||||
调用类型:
|
||||
</span>
|
||||
<span class="text-[12px] flex-1 text-foreground">
|
||||
{{
|
||||
getThingModelServiceCallTypeLabel(selectedProperty.callType)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<Button
|
||||
type="link"
|
||||
|
|
|
|||
|
|
@ -99,8 +99,7 @@ async function handleDelete(row: RuleSceneApi.SceneRule) {
|
|||
function hasTimerTrigger(row: RuleSceneApi.SceneRule): boolean {
|
||||
return (
|
||||
row.triggers?.some(
|
||||
(trigger) =>
|
||||
trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
(trigger) => trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
) || false
|
||||
);
|
||||
}
|
||||
|
|
@ -154,8 +153,7 @@ function getActionSummary(row: RuleSceneApi.SceneRule): string {
|
|||
/** 取定时触发器的 CRON 频率描述 */
|
||||
function getCronFrequency(row: RuleSceneApi.SceneRule): string {
|
||||
const timerTrigger = row.triggers?.find(
|
||||
(trigger) =>
|
||||
trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
(trigger) => trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
);
|
||||
return timerTrigger?.cronExpression
|
||||
? CronUtils.getFrequencyDescription(timerTrigger.cronExpression)
|
||||
|
|
@ -165,8 +163,7 @@ function getCronFrequency(row: RuleSceneApi.SceneRule): string {
|
|||
/** 取定时触发器原始 CRON 表达式 */
|
||||
function getCronExpression(row: RuleSceneApi.SceneRule): string {
|
||||
const timerTrigger = row.triggers?.find(
|
||||
(trigger) =>
|
||||
trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
(trigger) => trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
);
|
||||
return timerTrigger?.cronExpression || '';
|
||||
}
|
||||
|
|
@ -174,8 +171,7 @@ function getCronExpression(row: RuleSceneApi.SceneRule): string {
|
|||
/** 取定时触发器下次执行时间 */
|
||||
function getNextExecutionTime(row: RuleSceneApi.SceneRule): Date | null {
|
||||
const timerTrigger = row.triggers?.find(
|
||||
(trigger) =>
|
||||
trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
(trigger) => trigger.type === IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
);
|
||||
return timerTrigger?.cronExpression
|
||||
? CronUtils.getNextExecutionTime(timerTrigger.cronExpression)
|
||||
|
|
@ -327,7 +323,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
:title="row.description"
|
||||
placement="top"
|
||||
>
|
||||
<div class="mt-1 max-w-[200px] truncate text-xs text-muted-foreground">
|
||||
<div
|
||||
class="mt-1 max-w-[200px] truncate text-xs text-muted-foreground"
|
||||
>
|
||||
{{ row.description }}
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import type { ThingModelApi } from '#/api/iot/thingmodel';
|
|||
import { DICT_TYPE, getDataTypeOptionsLabel } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
<script lang="ts" setup>
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import {
|
||||
getDataTypeOptions,
|
||||
IoTDataSpecsDataTypeEnum,
|
||||
} from '@vben/constants';
|
||||
import { getDataTypeOptions, IoTDataSpecsDataTypeEnum } from '@vben/constants';
|
||||
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { Form, Input, Radio } from 'ant-design-vue';
|
||||
|
|
|
|||
|
|
@ -39,8 +39,9 @@ function validateEnumValue(_rule: any, value: any, callback: any) {
|
|||
callback(new Error('枚举值必须是数字'));
|
||||
return;
|
||||
}
|
||||
const sameCount = dataSpecsList.value.filter((it) => it.value === value)
|
||||
.length;
|
||||
const sameCount = dataSpecsList.value.filter(
|
||||
(it) => it.value === value,
|
||||
).length;
|
||||
if (sameCount > 1) {
|
||||
callback(new Error('枚举值不能重复'));
|
||||
return;
|
||||
|
|
@ -100,7 +101,10 @@ function validateEnumList(_rule: any, _value: any, callback: any) {
|
|||
]"
|
||||
class="mb-0 flex-1"
|
||||
>
|
||||
<Input v-model:value="item.value" placeholder="请输入枚举值,如「0」" />
|
||||
<Input
|
||||
v-model:value="item.value"
|
||||
placeholder="请输入枚举值,如「0」"
|
||||
/>
|
||||
</Form.Item>
|
||||
<span class="mx-2">~</span>
|
||||
<Form.Item
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@ function unitChange(unitSpecs: any) {
|
|||
</Form.Item>
|
||||
<Form.Item label="单位">
|
||||
<Select
|
||||
:value="
|
||||
dataSpecs.unit ? `${dataSpecs.unitName}-${dataSpecs.unit}` : ''
|
||||
"
|
||||
:value="dataSpecs.unit ? `${dataSpecs.unitName}-${dataSpecs.unit}` : ''"
|
||||
show-search
|
||||
placeholder="请选择单位"
|
||||
class="w-full"
|
||||
|
|
|
|||
|
|
@ -136,11 +136,7 @@ onMounted(() => {
|
|||
:wrapper-col="{ span: 18 }"
|
||||
class="mx-4"
|
||||
>
|
||||
<Form.Item
|
||||
:rules="ThingModelFormRules.name"
|
||||
label="参数名称"
|
||||
name="name"
|
||||
>
|
||||
<Form.Item :rules="ThingModelFormRules.name" label="参数名称" name="name">
|
||||
<Input v-model:value="formData.name" placeholder="请输入参数名称" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
|
|
|||
|
|
@ -111,7 +111,9 @@ function buildEmptyFormData(): ThingModelApi.ThingModel {
|
|||
}
|
||||
|
||||
/** 回显数据时,规整各分支字段确保子表单可绑定 */
|
||||
function normalizeFormData(result: ThingModelApi.ThingModel): ThingModelApi.ThingModel {
|
||||
function normalizeFormData(
|
||||
result: ThingModelApi.ThingModel,
|
||||
): ThingModelApi.ThingModel {
|
||||
const next: any = { ...result, type: Number(result.type) };
|
||||
if (isEmpty(next.property)) {
|
||||
next.dataType = IoTDataSpecsDataTypeEnum.INT;
|
||||
|
|
@ -141,46 +143,46 @@ function normalizeFormData(result: ThingModelApi.ThingModel): ThingModelApi.Thin
|
|||
/** 按功能类型将子表单数据回写到顶层,并清理无关分支 */
|
||||
function fillExtraAttributes(data: any) {
|
||||
switch (data.type) {
|
||||
case IoTThingModelTypeEnum.EVENT: {
|
||||
removeDataSpecs(data.event);
|
||||
data.dataType = data.event.dataType;
|
||||
data.event.identifier = data.identifier;
|
||||
data.event.name = data.name;
|
||||
if (isEmpty(data.event.outputParams)) {
|
||||
delete data.event.outputParams;
|
||||
}
|
||||
delete data.property;
|
||||
delete data.service;
|
||||
case IoTThingModelTypeEnum.EVENT: {
|
||||
removeDataSpecs(data.event);
|
||||
data.dataType = data.event.dataType;
|
||||
data.event.identifier = data.identifier;
|
||||
data.event.name = data.name;
|
||||
if (isEmpty(data.event.outputParams)) {
|
||||
delete data.event.outputParams;
|
||||
}
|
||||
delete data.property;
|
||||
delete data.service;
|
||||
|
||||
break;
|
||||
}
|
||||
case IoTThingModelTypeEnum.PROPERTY: {
|
||||
removeDataSpecs(data.property);
|
||||
data.dataType = data.property.dataType;
|
||||
data.property.identifier = data.identifier;
|
||||
data.property.name = data.name;
|
||||
delete data.service;
|
||||
delete data.event;
|
||||
|
||||
break;
|
||||
}
|
||||
case IoTThingModelTypeEnum.SERVICE: {
|
||||
removeDataSpecs(data.service);
|
||||
data.dataType = data.service.dataType;
|
||||
data.service.identifier = data.identifier;
|
||||
data.service.name = data.name;
|
||||
if (isEmpty(data.service.inputParams)) {
|
||||
delete data.service.inputParams;
|
||||
break;
|
||||
}
|
||||
if (isEmpty(data.service.outputParams)) {
|
||||
delete data.service.outputParams;
|
||||
}
|
||||
delete data.property;
|
||||
delete data.event;
|
||||
case IoTThingModelTypeEnum.PROPERTY: {
|
||||
removeDataSpecs(data.property);
|
||||
data.dataType = data.property.dataType;
|
||||
data.property.identifier = data.identifier;
|
||||
data.property.name = data.name;
|
||||
delete data.service;
|
||||
delete data.event;
|
||||
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
break;
|
||||
}
|
||||
case IoTThingModelTypeEnum.SERVICE: {
|
||||
removeDataSpecs(data.service);
|
||||
data.dataType = data.service.dataType;
|
||||
data.service.identifier = data.identifier;
|
||||
data.service.name = data.name;
|
||||
if (isEmpty(data.service.inputParams)) {
|
||||
delete data.service.inputParams;
|
||||
}
|
||||
if (isEmpty(data.service.outputParams)) {
|
||||
delete data.service.outputParams;
|
||||
}
|
||||
delete data.property;
|
||||
delete data.event;
|
||||
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -204,11 +206,7 @@ function removeDataSpecs(val: any) {
|
|||
:wrapper-col="{ span: 18 }"
|
||||
class="mx-4"
|
||||
>
|
||||
<Form.Item
|
||||
:rules="ThingModelFormRules.type"
|
||||
label="功能类型"
|
||||
name="type"
|
||||
>
|
||||
<Form.Item :rules="ThingModelFormRules.type" label="功能类型" name="type">
|
||||
<Radio.Group v-model:value="formData.type">
|
||||
<Radio.Button
|
||||
v-for="dict in getDictOptions(DICT_TYPE.IOT_THING_MODEL_TYPE)"
|
||||
|
|
@ -219,11 +217,7 @@ function removeDataSpecs(val: any) {
|
|||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
:rules="ThingModelFormRules.name"
|
||||
label="功能名称"
|
||||
name="name"
|
||||
>
|
||||
<Form.Item :rules="ThingModelFormRules.name" label="功能名称" name="name">
|
||||
<Input v-model:value="formData.name" placeholder="请输入功能名称" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
|
|
|||
|
|
@ -135,11 +135,7 @@ function deleteParamItem(index: number) {
|
|||
:wrapper-col="{ span: 18 }"
|
||||
class="mx-4"
|
||||
>
|
||||
<Form.Item
|
||||
:rules="ThingModelFormRules.name"
|
||||
label="参数名称"
|
||||
name="name"
|
||||
>
|
||||
<Form.Item :rules="ThingModelFormRules.name" label="参数名称" name="name">
|
||||
<Input v-model:value="formData.name" placeholder="请输入参数名称" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
|
|
|
|||
|
|
@ -137,10 +137,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
|
|||
v-if="property.dataType === IoTDataSpecsDataTypeEnum.BOOL"
|
||||
label="布尔值"
|
||||
>
|
||||
<template
|
||||
v-for="(item, index) in property.dataSpecsList"
|
||||
:key="item.value"
|
||||
>
|
||||
<template v-for="(item, index) in property.dataSpecsList" :key="item.value">
|
||||
<div class="mb-[5px] flex w-full items-center justify-start">
|
||||
<span>{{ item.value }}</span>
|
||||
<span class="mx-2">-</span>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ const [Modal, modalApi] = useVbenModal({
|
|||
modalApi.lock();
|
||||
try {
|
||||
// 加载数据
|
||||
thingModelTSL.value = await getThingModelTSLByProductId(product?.value?.id || 0);
|
||||
thingModelTSL.value = await getThingModelTSLByProductId(
|
||||
product?.value?.id || 0,
|
||||
);
|
||||
// 设置到 values
|
||||
tslString.value = JSON.stringify(thingModelTSL.value, null, 2);
|
||||
} finally {
|
||||
|
|
@ -64,7 +66,9 @@ watch(tslString, (newValue) => {
|
|||
v-if="viewMode === 'view'"
|
||||
class="max-h-[600px] overflow-y-auto rounded border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<pre class="m-0 whitespace-pre-wrap break-words font-mono text-[13px] leading-normal"><code>{{ formattedTSL }}</code></pre>
|
||||
<pre
|
||||
class="m-0 whitespace-pre-wrap break-words font-mono text-[13px] leading-normal"
|
||||
><code>{{ formattedTSL }}</code></pre>
|
||||
</div>
|
||||
<!-- 编辑器视图:可编辑 -->
|
||||
<Textarea
|
||||
|
|
|
|||
|
|
@ -270,10 +270,7 @@ export function usePartFormSchema(): VbenFormSchema[] {
|
|||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(
|
||||
DICT_TYPE.MES_MD_AUTO_CODE_PART_TYPE,
|
||||
'number',
|
||||
),
|
||||
options: getDictOptions(DICT_TYPE.MES_MD_AUTO_CODE_PART_TYPE, 'number'),
|
||||
placeholder: '请选择分段类型',
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { nextTick, ref } from 'vue';
|
|||
|
||||
import { CommonStatusEnum } from '@vben/constants';
|
||||
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { Button, message, Modal } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getClientPage } from '#/api/mes/md/client';
|
||||
|
|
@ -47,13 +47,33 @@ async function waitTableReady(): Promise<void> {
|
|||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!multiple.value) {
|
||||
const selected = checked && row ? [row] : [];
|
||||
selectedRows.value = selected;
|
||||
await syncSingleSelection(selected[0]);
|
||||
return;
|
||||
for (let index = 0; index < MAX_TABLE_READY_FRAMES; index += 1) {
|
||||
if (queryFinished.value) {
|
||||
const rows = getTableRows();
|
||||
if (latestQueryRows.value.length === 0 && rows.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (latestQueryRows.value.length > 0 && rows.length > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await waitNextFrame();
|
||||
}
|
||||
selectedRows.value = records;
|
||||
}
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, MesMdClientApi.Client>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as MesMdClientApi.Client[];
|
||||
records.forEach((row) => {
|
||||
if (row.id !== null) {
|
||||
selectedMap.set(row.id as number, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理勾选变化 */
|
||||
|
|
@ -92,7 +112,7 @@ async function applyPreSelection() {
|
|||
// proxy 表格回显选中时要读取 fullData,否则首次打开可能读不到刚查询出的数据。
|
||||
const rows = getTableRows();
|
||||
for (const row of rows) {
|
||||
if (row.id == null || !preSelectedIds.value.includes(row.id)) {
|
||||
if (row.id === null || !preSelectedIds.value.includes(row.id as number)) {
|
||||
continue;
|
||||
}
|
||||
if (multiple.value) {
|
||||
|
|
@ -169,14 +189,19 @@ async function resetQueryState() {
|
|||
}
|
||||
|
||||
/** 打开客户选择弹窗 */
|
||||
async function openModal(selectedIds?: number[], options?: { multiple?: boolean }) {
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? true;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
latestQueryRows.value = [];
|
||||
queryFinished.value = false;
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({ columns: useClientSelectGridColumns(multiple.value) });
|
||||
gridApi.setGridOptions({
|
||||
columns: useClientSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
|
|
@ -213,5 +238,9 @@ defineExpose({ open: openModal });
|
|||
@cancel="closeModal"
|
||||
>
|
||||
<Grid table-title="客户列表" />
|
||||
<template #footer>
|
||||
<Button @click="closeModal"> 取消 </Button>
|
||||
<Button type="primary" @click="handleConfirm"> 确定 </Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -37,13 +37,18 @@ const hovering = ref(false); // 是否悬停
|
|||
const selectedItem = ref<MesMdClientApi.Client>(); // 当前选中客户
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||
const showClear = computed( // 是否显示清空图标
|
||||
() => props.allowClear && !props.disabled && hovering.value && props.modelValue != null,
|
||||
const showClear = computed(
|
||||
// 是否显示清空图标
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue !== null,
|
||||
);
|
||||
|
||||
/** 根据客户编号回显选择器 */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
if (id === null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
|
|
@ -51,7 +56,7 @@ async function resolveItemById(id: number | undefined) {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
selectedItem.value = await getClient(id);
|
||||
selectedItem.value = await getClient(id as number);
|
||||
} catch (error) {
|
||||
console.error('[MdClientSelect] resolveItemById failed:', error);
|
||||
}
|
||||
|
|
@ -83,8 +88,8 @@ function handleClick(event: MouseEvent) {
|
|||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
||||
}
|
||||
|
||||
/** 回填选中的客户 */
|
||||
|
|
|
|||
|
|
@ -144,7 +144,10 @@ async function resetQueryState() {
|
|||
}
|
||||
|
||||
/** 打开物料选择弹窗 */
|
||||
async function openModal(selectedIds?: number[], options?: { multiple?: boolean }) {
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? true;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
|
|
@ -167,7 +170,10 @@ function handleConfirm() {
|
|||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? selectedRows.value : [selectedRows.value[0]!]);
|
||||
emit(
|
||||
'selected',
|
||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
||||
);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +191,10 @@ defineExpose({ open: openModal });
|
|||
>
|
||||
<div class="flex h-full w-full">
|
||||
<Card class="mr-4 h-full w-1/5">
|
||||
<MdItemTypeTree ref="typeTreeRef" @node-click="handleItemTypeNodeClick" />
|
||||
<MdItemTypeTree
|
||||
ref="typeTreeRef"
|
||||
@node-click="handleItemTypeNodeClick"
|
||||
/>
|
||||
</Card>
|
||||
<div class="w-4/5">
|
||||
<Grid table-title="物料产品列表" />
|
||||
|
|
|
|||
|
|
@ -37,13 +37,18 @@ const hovering = ref(false); // 是否悬停
|
|||
const selectedItem = ref<MesMdItemApi.Item>(); // 当前选中物料
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||
const showClear = computed( // 是否显示清空图标
|
||||
() => props.allowClear && !props.disabled && hovering.value && props.modelValue != null,
|
||||
const showClear = computed(
|
||||
// 是否显示清空图标
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue !== null,
|
||||
);
|
||||
|
||||
/** 根据物料编号回显选择器 */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
if (id === null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
|
|
@ -51,7 +56,7 @@ async function resolveItemById(id: number | undefined) {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
selectedItem.value = await getItem(id);
|
||||
selectedItem.value = await getItem(id as number);
|
||||
} catch (error) {
|
||||
console.error('[MdItemSelect] resolveItemById failed:', error);
|
||||
}
|
||||
|
|
@ -83,8 +88,8 @@ function handleClick(event: MouseEvent) {
|
|||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
||||
}
|
||||
|
||||
/** 回填选中的物料 */
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ async function openModal(itemId: number, selectedBomItemId?: number) {
|
|||
list.value = await getProductBomListByItemId(itemId);
|
||||
gridApi.setGridOptions({ data: list.value });
|
||||
await nextTick();
|
||||
if (selectedBomItemId != null) {
|
||||
if (selectedBomItemId !== null) {
|
||||
const match = list.value.find(
|
||||
(row) => row.bomItemId === selectedBomItemId,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -39,17 +39,18 @@ const hovering = ref(false); // 是否悬停
|
|||
const selectedBom = ref<MesMdProductBomApi.ProductBom>(); // 当前选中的 BOM 物料
|
||||
|
||||
const displayLabel = computed(() => selectedBom.value?.bomItemName ?? ''); // 选择器展示名称
|
||||
const showClear = computed( // 是否显示清空图标
|
||||
const showClear = computed(
|
||||
// 是否显示清空图标
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
props.modelValue !== null,
|
||||
);
|
||||
|
||||
/** 根据 BOM 子物料编号回显选择器 */
|
||||
async function resolveBomById(bomItemId: number | undefined) {
|
||||
if (bomItemId == null || props.itemId == null) {
|
||||
if (bomItemId === null || props.itemId === null) {
|
||||
selectedBom.value = undefined;
|
||||
return;
|
||||
}
|
||||
|
|
@ -57,7 +58,7 @@ async function resolveBomById(bomItemId: number | undefined) {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
const list = await getProductBomListByItemId(props.itemId);
|
||||
const list = await getProductBomListByItemId(props.itemId as number);
|
||||
selectedBom.value = list.find((item) => item.bomItemId === bomItemId);
|
||||
} catch (error) {
|
||||
console.error('[MdProductBomSelect] resolveBomById failed:', error);
|
||||
|
|
@ -90,7 +91,7 @@ function clearSelected() {
|
|||
|
||||
/** 打开 BOM 物料选择弹窗 */
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (props.disabled || props.itemId == null) {
|
||||
if (props.disabled || props.itemId === null) {
|
||||
return;
|
||||
}
|
||||
const target = event.target as HTMLElement;
|
||||
|
|
@ -99,7 +100,7 @@ function handleClick(event: MouseEvent) {
|
|||
clearSelected();
|
||||
return;
|
||||
}
|
||||
dialogRef.value?.open(props.itemId, props.modelValue);
|
||||
dialogRef.value?.open(props.itemId as number, props.modelValue);
|
||||
}
|
||||
|
||||
/** 回填选中的 BOM 物料 */
|
||||
|
|
|
|||
|
|
@ -89,7 +89,10 @@ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
|||
component: markRaw(MdItemTypeSelect),
|
||||
componentProps: {
|
||||
onChange: async (itemType: any) => {
|
||||
await formApi?.setFieldValue('itemOrProduct', itemType?.itemOrProduct);
|
||||
await formApi?.setFieldValue(
|
||||
'itemOrProduct',
|
||||
itemType?.itemOrProduct,
|
||||
);
|
||||
},
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
|
|
@ -410,54 +413,55 @@ export function useItemSelectGridColumns(): VxeTableGridOptions<MesMdItemApi.Ite
|
|||
export function useProductBomGridColumns(
|
||||
isReadOnly = false,
|
||||
): VxeTableGridOptions<MesMdProductBomApi.ProductBom>['columns'] {
|
||||
const columns: VxeTableGridOptions<MesMdProductBomApi.ProductBom>['columns'] = [
|
||||
{
|
||||
field: 'bomItemCode',
|
||||
title: '物料编码',
|
||||
minWidth: 160,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'bomItemName',
|
||||
title: '物料名称',
|
||||
minWidth: 160,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'bomItemSpecification',
|
||||
title: '规格型号',
|
||||
minWidth: 140,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'unitMeasureName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'itemOrProduct',
|
||||
title: '物料/产品',
|
||||
width: 110,
|
||||
align: 'center',
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_MD_ITEM_OR_PRODUCT },
|
||||
const columns: VxeTableGridOptions<MesMdProductBomApi.ProductBom>['columns'] =
|
||||
[
|
||||
{
|
||||
field: 'bomItemCode',
|
||||
title: '物料编码',
|
||||
minWidth: 160,
|
||||
align: 'center',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: '用量比例',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
title: '备注',
|
||||
minWidth: 140,
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
{
|
||||
field: 'bomItemName',
|
||||
title: '物料名称',
|
||||
minWidth: 160,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'bomItemSpecification',
|
||||
title: '规格型号',
|
||||
minWidth: 140,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'unitMeasureName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'itemOrProduct',
|
||||
title: '物料/产品',
|
||||
width: 110,
|
||||
align: 'center',
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_MD_ITEM_OR_PRODUCT },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: '用量比例',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
title: '备注',
|
||||
minWidth: 140,
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
|
||||
if (!isReadOnly) {
|
||||
columns.push({
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ const getTitle = computed(() => {
|
|||
};
|
||||
return titles[formMode.value];
|
||||
});
|
||||
const currentItemOrProduct = computed(() => formData.value?.itemOrProduct || ''); // 当前物料/产品标识
|
||||
const currentItemOrProduct = computed(
|
||||
() => formData.value?.itemOrProduct || '',
|
||||
); // 当前物料/产品标识
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
|
|
|
|||
|
|
@ -98,29 +98,80 @@ watch(
|
|||
<Button type="primary" @click="handleSave">保存批次属性</Button>
|
||||
</div>
|
||||
<div class="grid grid-cols-5 gap-x-5 gap-y-3">
|
||||
<Checkbox v-model:checked="formData.produceDateFlag" :disabled="isReadOnly">生产日期</Checkbox>
|
||||
<Checkbox v-model:checked="formData.qualityStatusFlag" :disabled="isReadOnly">质量状态</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.produceDateFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
生产日期
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.qualityStatusFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
质量状态
|
||||
</Checkbox>
|
||||
|
||||
<template v-if="itemOrProduct === MesItemOrProductEnum.ITEM.value">
|
||||
<Checkbox v-model:checked="formData.vendorFlag" :disabled="isReadOnly">供应商</Checkbox>
|
||||
<Checkbox v-model:checked="formData.purchaseOrderCodeFlag" :disabled="isReadOnly">
|
||||
<Checkbox v-model:checked="formData.vendorFlag" :disabled="isReadOnly">
|
||||
供应商
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.purchaseOrderCodeFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
采购订单编号
|
||||
</Checkbox>
|
||||
<Checkbox v-model:checked="formData.lotNumberFlag" :disabled="isReadOnly">生产批号</Checkbox>
|
||||
<Checkbox v-model:checked="formData.expireDateFlag" :disabled="isReadOnly">有效期</Checkbox>
|
||||
<Checkbox v-model:checked="formData.receiptDateFlag" :disabled="isReadOnly">入库日期</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.lotNumberFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
生产批号
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.expireDateFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
有效期
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.receiptDateFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
入库日期
|
||||
</Checkbox>
|
||||
</template>
|
||||
|
||||
<template v-if="itemOrProduct === MesItemOrProductEnum.PRODUCT.value">
|
||||
<Checkbox v-model:checked="formData.clientFlag" :disabled="isReadOnly">客户</Checkbox>
|
||||
<Checkbox v-model:checked="formData.salesOrderCodeFlag" :disabled="isReadOnly">
|
||||
<Checkbox v-model:checked="formData.clientFlag" :disabled="isReadOnly">
|
||||
客户
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.salesOrderCodeFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
销售订单编号
|
||||
</Checkbox>
|
||||
<Checkbox v-model:checked="formData.workorderFlag" :disabled="isReadOnly">生产工单</Checkbox>
|
||||
<Checkbox v-model:checked="formData.taskFlag" :disabled="isReadOnly">生产任务</Checkbox>
|
||||
<Checkbox v-model:checked="formData.workstationFlag" :disabled="isReadOnly">工作站</Checkbox>
|
||||
<Checkbox v-model:checked="formData.toolFlag" :disabled="isReadOnly">工具</Checkbox>
|
||||
<Checkbox v-model:checked="formData.moldFlag" :disabled="isReadOnly">模具</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.workorderFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
生产工单
|
||||
</Checkbox>
|
||||
<Checkbox v-model:checked="formData.taskFlag" :disabled="isReadOnly">
|
||||
生产任务
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
v-model:checked="formData.workstationFlag"
|
||||
:disabled="isReadOnly"
|
||||
>
|
||||
工作站
|
||||
</Checkbox>
|
||||
<Checkbox v-model:checked="formData.toolFlag" :disabled="isReadOnly">
|
||||
工具
|
||||
</Checkbox>
|
||||
<Checkbox v-model:checked="formData.moldFlag" :disabled="isReadOnly">
|
||||
模具
|
||||
</Checkbox>
|
||||
</template>
|
||||
</div>
|
||||
</Spin>
|
||||
|
|
|
|||
|
|
@ -47,9 +47,21 @@ const [Form, formApi] = useVbenForm({
|
|||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{ fieldName: 'id', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{ fieldName: 'itemId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{ fieldName: 'bomItemId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'bomItemId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'bomItemCode',
|
||||
label: 'BOM 物料编码',
|
||||
|
|
@ -164,7 +176,9 @@ async function submitForm() {
|
|||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MesMdProductBomApi.ProductBom;
|
||||
await (formData.value?.id ? updateProductBom(data) : createProductBom(data));
|
||||
await (formData.value?.id
|
||||
? updateProductBom(data)
|
||||
: createProductBom(data));
|
||||
formOpen.value = false;
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
await getList();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,16 @@ import type { MesMdProductSopApi } from '#/api/mes/md/item/productSop';
|
|||
|
||||
import { computed, markRaw, ref, watch } from 'vue';
|
||||
|
||||
import { Button, Card, Empty, Image, message, Modal, Popconfirm, Spin } from 'ant-design-vue';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Empty,
|
||||
Image,
|
||||
message,
|
||||
Modal,
|
||||
Popconfirm,
|
||||
Spin,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm, z } from '#/adapter/form';
|
||||
import {
|
||||
|
|
@ -23,9 +32,7 @@ import { ImageUpload } from '#/components/upload';
|
|||
import { ProProcessSelect } from '#/views/mes/pro/process/components';
|
||||
|
||||
type MediaKind = 'SIP' | 'SOP';
|
||||
type MediaItem =
|
||||
| MesMdProductSipApi.ProductSip
|
||||
| MesMdProductSopApi.ProductSop;
|
||||
type MediaItem = MesMdProductSipApi.ProductSip | MesMdProductSopApi.ProductSop;
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
|
@ -56,8 +63,16 @@ const [Form, formApi] = useVbenForm({
|
|||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{ fieldName: 'id', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{ fieldName: 'itemId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'title',
|
||||
label: '标题',
|
||||
|
|
@ -152,7 +167,9 @@ async function submitForm() {
|
|||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MediaItem;
|
||||
await (formData.value?.id ? updateApi()(data as any) : createApi()(data as any));
|
||||
await (formData.value?.id
|
||||
? updateApi()(data as any)
|
||||
: createApi()(data as any));
|
||||
formOpen.value = false;
|
||||
message.success('保存成功');
|
||||
await getList();
|
||||
|
|
@ -181,12 +198,7 @@ watch(
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<Button
|
||||
v-if="!isReadOnly"
|
||||
class="mb-3"
|
||||
type="primary"
|
||||
@click="openForm()"
|
||||
>
|
||||
<Button v-if="!isReadOnly" class="mb-3" type="primary" @click="openForm()">
|
||||
添加 {{ title }}
|
||||
</Button>
|
||||
<Spin :spinning="loading">
|
||||
|
|
@ -215,8 +227,13 @@ watch(
|
|||
{{ item.description }}
|
||||
</div>
|
||||
<div v-if="!isReadOnly" class="mt-2 flex justify-end">
|
||||
<Button type="link" size="small" @click="openForm(item)">编辑</Button>
|
||||
<Popconfirm title="确认删除该数据吗?" @confirm="handleDelete(item.id!)">
|
||||
<Button type="link" size="small" @click="openForm(item)">
|
||||
编辑
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="确认删除该数据吗?"
|
||||
@confirm="handleDelete(item.id!)"
|
||||
>
|
||||
<Button danger type="link" size="small">删除</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ const allList = ref<MesMdItemTypeApi.ItemType[]>([]); // 物料分类列表
|
|||
const itemTypeTree = ref<ItemTypeNode[]>([]); // 物料分类树
|
||||
const selectedItem = ref<MesMdItemTypeApi.ItemType>(); // 当前选中分类
|
||||
|
||||
const selectValue = computed({ // 选择器绑定值
|
||||
const selectValue = computed({
|
||||
// 选择器绑定值
|
||||
get: () => props.modelValue,
|
||||
set: (value: number | undefined) => {
|
||||
emit('update:modelValue', value);
|
||||
|
|
@ -48,7 +49,9 @@ const selectValue = computed({ // 选择器绑定值
|
|||
});
|
||||
|
||||
/** 递归将有子节点的分支节点标记为 disabled */
|
||||
function markParentsDisabled(nodes: MesMdItemTypeApi.ItemType[]): ItemTypeNode[] {
|
||||
function markParentsDisabled(
|
||||
nodes: MesMdItemTypeApi.ItemType[],
|
||||
): ItemTypeNode[] {
|
||||
return nodes.map((node) => {
|
||||
const children = node.children?.length
|
||||
? markParentsDisabled(node.children)
|
||||
|
|
@ -64,7 +67,9 @@ function markParentsDisabled(nodes: MesMdItemTypeApi.ItemType[]): ItemTypeNode[]
|
|||
/** 根据当前值同步 tooltip 展示的分类详情 */
|
||||
function syncSelectedItem(value: number | undefined) {
|
||||
selectedItem.value =
|
||||
value === undefined ? undefined : allList.value.find((item) => item.id === value);
|
||||
value === undefined
|
||||
? undefined
|
||||
: allList.value.find((item) => item.id === value);
|
||||
}
|
||||
|
||||
/** 除 v-model 外,额外抛出完整分类对象给业务表单使用 */
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ const allList = ref<MesMdUnitMeasureApi.UnitMeasure[]>([]); // 计量单位列
|
|||
const filteredList = ref<MesMdUnitMeasureApi.UnitMeasure[]>([]); // 过滤后的计量单位列表
|
||||
const selectedItem = ref<MesMdUnitMeasureApi.UnitMeasure>(); // 当前选中计量单位
|
||||
|
||||
const selectValue = computed({ // 选择器绑定值
|
||||
const selectValue = computed({
|
||||
// 选择器绑定值
|
||||
get: () => props.modelValue,
|
||||
set: (value: number | undefined) => {
|
||||
emit('update:modelValue', value);
|
||||
|
|
@ -46,14 +47,16 @@ function handleFilter(input: string, option: any) {
|
|||
const item = option?.item as MesMdUnitMeasureApi.UnitMeasure | undefined;
|
||||
return Boolean(
|
||||
item?.name?.toLowerCase().includes(keyword) ||
|
||||
item?.code?.toLowerCase().includes(keyword),
|
||||
item?.code?.toLowerCase().includes(keyword),
|
||||
);
|
||||
}
|
||||
|
||||
/** 根据当前值同步 tooltip 展示的计量单位详情 */
|
||||
function syncSelectedItem(value: number | undefined) {
|
||||
selectedItem.value =
|
||||
value === undefined ? undefined : allList.value.find((item) => item.id === value);
|
||||
value === undefined
|
||||
? undefined
|
||||
: allList.value.find((item) => item.id === value);
|
||||
}
|
||||
|
||||
/** 除 v-model 外,额外抛出完整计量单位对象给业务表单使用 */
|
||||
|
|
@ -84,7 +87,9 @@ onMounted(async () => {
|
|||
<div>编码:{{ selectedItem.code || '-' }}</div>
|
||||
<div>名称:{{ selectedItem.name || '-' }}</div>
|
||||
<div>是否主单位:{{ selectedItem.primaryFlag ? '是' : '否' }}</div>
|
||||
<div v-if="!selectedItem.primaryFlag && selectedItem.changeRate != null">
|
||||
<div
|
||||
v-if="!selectedItem.primaryFlag && selectedItem.changeRate != null"
|
||||
>
|
||||
换算比例:{{ selectedItem.changeRate }}
|
||||
</div>
|
||||
<div v-if="selectedItem.remark">备注:{{ selectedItem.remark }}</div>
|
||||
|
|
|
|||
|
|
@ -132,7 +132,10 @@ async function resetQueryState() {
|
|||
}
|
||||
|
||||
/** 打开供应商选择弹窗 */
|
||||
async function openModal(selectedIds?: number[], options?: { multiple?: boolean }) {
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? true;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
|
|
@ -155,7 +158,10 @@ function handleConfirm() {
|
|||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? selectedRows.value : [selectedRows.value[0]!]);
|
||||
emit(
|
||||
'selected',
|
||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
||||
);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,13 +37,18 @@ const hovering = ref(false); // 是否悬停
|
|||
const selectedItem = ref<MesMdVendorApi.Vendor>(); // 当前选中供应商
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||
const showClear = computed( // 是否显示清空图标
|
||||
() => props.allowClear && !props.disabled && hovering.value && props.modelValue != null,
|
||||
const showClear = computed(
|
||||
// 是否显示清空图标
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue !== null,
|
||||
);
|
||||
|
||||
/** 根据供应商编号回显选择器 */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
if (id === null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
|
|
@ -51,7 +56,7 @@ async function resolveItemById(id: number | undefined) {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
selectedItem.value = await getVendor(id);
|
||||
selectedItem.value = await getVendor(id as number);
|
||||
} catch (error) {
|
||||
console.error('[MdVendorSelect] resolveItemById failed:', error);
|
||||
}
|
||||
|
|
@ -83,8 +88,8 @@ function handleClick(event: MouseEvent) {
|
|||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
||||
}
|
||||
|
||||
/** 回填选中的供应商 */
|
||||
|
|
|
|||
|
|
@ -44,14 +44,16 @@ function handleFilter(input: string, option: any) {
|
|||
const item = option?.item as MesMdWorkshopApi.Workshop | undefined;
|
||||
return Boolean(
|
||||
item?.name?.toLowerCase().includes(keyword) ||
|
||||
item?.code?.toLowerCase().includes(keyword),
|
||||
item?.code?.toLowerCase().includes(keyword),
|
||||
);
|
||||
}
|
||||
|
||||
/** 根据当前值同步 tooltip 展示的车间详情 */
|
||||
function syncSelectedItem(value: number | undefined) {
|
||||
selectedItem.value =
|
||||
value === undefined ? undefined : allList.value.find((item) => item.id === value);
|
||||
value === undefined
|
||||
? undefined
|
||||
: allList.value.find((item) => item.id === value);
|
||||
}
|
||||
|
||||
/** 除 v-model 外,额外抛出完整车间对象给业务表单使用 */
|
||||
|
|
@ -80,7 +82,11 @@ onMounted(async () => {
|
|||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>编码:{{ selectedItem.code || '-' }}</div>
|
||||
<div>名称:{{ selectedItem.name || '-' }}</div>
|
||||
<div>面积:{{ selectedItem.area != null ? `${selectedItem.area} ㎡` : '-' }}</div>
|
||||
<div>
|
||||
面积:{{
|
||||
selectedItem.area != null ? `${selectedItem.area} ㎡` : '-'
|
||||
}}
|
||||
</div>
|
||||
<div>负责人:{{ selectedItem.chargeUserName || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -69,7 +69,11 @@ async function handleCheckboxChange({
|
|||
}
|
||||
|
||||
/** 处理全选变化 */
|
||||
function handleCheckboxAll({ records }: { records: MesMdWorkstationApi.Workstation[] }) {
|
||||
function handleCheckboxAll({
|
||||
records,
|
||||
}: {
|
||||
records: MesMdWorkstationApi.Workstation[];
|
||||
}) {
|
||||
if (syncingSingleSelection.value) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -143,7 +147,10 @@ async function resetQueryState() {
|
|||
}
|
||||
|
||||
/** 打开工作站选择弹窗 */
|
||||
async function openModal(selectedIds?: number[], options?: { multiple?: boolean }) {
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? true;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
|
|
@ -166,7 +173,10 @@ function handleConfirm() {
|
|||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? selectedRows.value : [selectedRows.value[0]!]);
|
||||
emit(
|
||||
'selected',
|
||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
||||
);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,13 +39,18 @@ const hovering = ref(false); // 是否悬停
|
|||
const selectedItem = ref<MesMdWorkstationApi.Workstation>(); // 选中的工作站
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.name ?? ''); // 选择器展示名称
|
||||
const showClear = computed( // 是否显示清空图标
|
||||
() => props.allowClear && !props.disabled && hovering.value && props.modelValue != null,
|
||||
const showClear = computed(
|
||||
// 是否显示清空图标
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue !== null,
|
||||
);
|
||||
|
||||
/** 根据工作站编号回显选择器 */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
if (id === null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
|
|
@ -53,7 +58,7 @@ async function resolveItemById(id: number | undefined) {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
selectedItem.value = await getWorkstation(id);
|
||||
selectedItem.value = await getWorkstation(id as number);
|
||||
} catch (error) {
|
||||
console.error('[MdWorkstationSelect] resolveItemById failed:', error);
|
||||
}
|
||||
|
|
@ -85,8 +90,8 @@ function handleClick(event: MouseEvent) {
|
|||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||
const selectedIds = props.modelValue === null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds as number[], { multiple: false });
|
||||
}
|
||||
|
||||
/** 回填选中的工作站 */
|
||||
|
|
|
|||
|
|
@ -43,7 +43,11 @@ const [Form, formApi] = useVbenForm({
|
|||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{ fieldName: 'workstationId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{
|
||||
fieldName: 'workstationId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'machineryId',
|
||||
label: '设备',
|
||||
|
|
@ -140,7 +144,8 @@ async function submitForm() {
|
|||
}
|
||||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MesMdWorkstationMachineApi.WorkstationMachine;
|
||||
const data =
|
||||
(await formApi.getValues()) as MesMdWorkstationMachineApi.WorkstationMachine;
|
||||
await createWorkstationMachine(data);
|
||||
formOpen.value = false;
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
|
|
|
|||
|
|
@ -45,8 +45,16 @@ const [Form, formApi] = useVbenForm({
|
|||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{ fieldName: 'id', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{ fieldName: 'workstationId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'workstationId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'toolTypeId',
|
||||
label: '工具类型',
|
||||
|
|
@ -149,8 +157,11 @@ async function submitForm() {
|
|||
}
|
||||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MesMdWorkstationToolApi.WorkstationTool;
|
||||
await (formData.value?.id ? updateWorkstationTool(data) : createWorkstationTool(data));
|
||||
const data =
|
||||
(await formApi.getValues()) as MesMdWorkstationToolApi.WorkstationTool;
|
||||
await (formData.value?.id
|
||||
? updateWorkstationTool(data)
|
||||
: createWorkstationTool(data));
|
||||
formOpen.value = false;
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
await getList();
|
||||
|
|
|
|||
|
|
@ -45,8 +45,16 @@ const [Form, formApi] = useVbenForm({
|
|||
},
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{ fieldName: 'id', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{ fieldName: 'workstationId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'workstationId',
|
||||
component: 'Input',
|
||||
dependencies: { triggerFields: [''], show: () => false },
|
||||
},
|
||||
{
|
||||
fieldName: 'postId',
|
||||
label: '岗位',
|
||||
|
|
@ -145,8 +153,11 @@ async function submitForm() {
|
|||
}
|
||||
formLoading.value = true;
|
||||
try {
|
||||
const data = (await formApi.getValues()) as MesMdWorkstationWorkerApi.WorkstationWorker;
|
||||
await (formData.value?.id ? updateWorkstationWorker(data) : createWorkstationWorker(data));
|
||||
const data =
|
||||
(await formApi.getValues()) as MesMdWorkstationWorkerApi.WorkstationWorker;
|
||||
await (formData.value?.id
|
||||
? updateWorkstationWorker(data)
|
||||
: createWorkstationWorker(data));
|
||||
formOpen.value = false;
|
||||
message.success($t('ui.actionMessage.operationSuccess'));
|
||||
await getList();
|
||||
|
|
|
|||
|
|
@ -44,14 +44,16 @@ function handleFilter(input: string, option: any) {
|
|||
const item = option?.item as MesProProcessApi.Process | undefined;
|
||||
return Boolean(
|
||||
item?.name?.toLowerCase().includes(keyword) ||
|
||||
item?.code?.toLowerCase().includes(keyword),
|
||||
item?.code?.toLowerCase().includes(keyword),
|
||||
);
|
||||
}
|
||||
|
||||
/** 根据当前值同步 tooltip 展示的工序详情 */
|
||||
function syncSelectedItem(value: number | undefined) {
|
||||
selectedItem.value =
|
||||
value === undefined ? undefined : allList.value.find((item) => item.id === value);
|
||||
value === undefined
|
||||
? undefined
|
||||
: allList.value.find((item) => item.id === value);
|
||||
}
|
||||
|
||||
/** 除 v-model 外,额外抛出完整工序对象给业务表单使用 */
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue