pull/348/MERGE
xingyu4j 2026-05-23 18:39:12 +08:00
commit fb2595ef90
462 changed files with 12563 additions and 7574 deletions

View File

@ -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

View File

@ -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

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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.

3
.gitignore vendored
View File

@ -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
View File

@ -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

View File

@ -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,

View File

@ -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'),
// 自定义主要按钮

View File

@ -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',
);
}
/** 新增数据流转目的 */

View File

@ -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' }],
};

View File

@ -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 },
);
}

View File

@ -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 } },
);
}
/** 保存假期设置 */

View File

@ -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 },
);
}
/** 查询排班计划详情 */

View File

@ -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}`,
);
}
/** 新增计划班次 */

View File

@ -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}`,
);
}
/** 新增计划班组关联 */

View File

@ -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 },
);
}
/** 查询班组列表 */

View File

@ -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(',') },
},
);
}

View File

@ -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}`,
);
}
/** 新增点检保养方案 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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,
});
}

View File

@ -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);
}

View File

@ -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 },
);
}

View 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}`,
);
}
/** 新增设备类型 */

View File

@ -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,
});
}

View File

@ -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);
}

View File

@ -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}`,
);
}
/** 新增维修工单 */

View File

@ -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}`,
);
}
/** 新增维修工单行 */

View File

@ -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}`,
);
}
/** 新增点检保养项目 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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,
});
}

View File

@ -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,
});
}
/** 查询工具精简列表 */

View File

@ -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}`,
);
}
/** 新增工具类型 */

View File

@ -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>

View File

@ -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'),
},
],
},

View File

@ -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',

View File

@ -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" />

View File

@ -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"

View File

@ -134,7 +134,9 @@ const [Modal, modalApi] = useVbenModal({
advValues.latitude !== null &&
advValues.latitude !== '';
if (hasLongitude !== hasLatitude) {
message.warning(hasLongitude ? '请同时填写设备纬度' : '请同时填写设备经度');
message.warning(
hasLongitude ? '请同时填写设备纬度' : '请同时填写设备经度',
);
return;
}
}

View File

@ -122,7 +122,6 @@ async function renderChartWhenReady() {
await nextTick();
initChart();
}
</script>
<template>

View File

@ -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 || '-';
}
/** 固件详情的描述字段 */

View File

@ -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 }">

View File

@ -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="联网方式"
>

View File

@ -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"

View File

@ -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';

View File

@ -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

View File

@ -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="请选择请求方法">

View File

@ -1,5 +1,4 @@
<script lang="ts" setup>
import { onMounted } from 'vue';
import { isEmpty } from '@vben/utils';

View File

@ -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" />

View File

@ -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']"

View File

@ -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']"

View File

@ -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

View File

@ -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="请选择数据格式">

View File

@ -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="请选择数据格式">

View File

@ -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"
>

View File

@ -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;
//

View File

@ -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>

View File

@ -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"

View File

@ -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"

View File

@ -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 回调值类型为 ValueTypestring | 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>

View File

@ -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">

View File

@ -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" />

View File

@ -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">

View File

@ -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"

View File

@ -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>

View File

@ -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 [

View File

@ -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';

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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',

View File

@ -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>

View File

@ -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 });
}
/** 回填选中的客户 */

View File

@ -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="" />

View File

@ -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 });
}
/** 回填选中的物料 */

View File

@ -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,
);

View File

@ -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 物料 */

View File

@ -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({

View File

@ -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: {

View File

@ -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>

View File

@ -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();

View File

@ -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>

View File

@ -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 外,额外抛出完整分类对象给业务表单使用 */

View File

@ -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>

View File

@ -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;
}

View File

@ -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 });
}
/** 回填选中的供应商 */

View File

@ -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>

View File

@ -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;
}

View File

@ -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 });
}
/** 回填选中的工作站 */

View File

@ -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'));

View File

@ -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();

View File

@ -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();

View File

@ -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