From a7dc7b230fcc6abc6ee5a7bfadb90789b03d2ca8 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期一, 07 九月 2026 16:45:37 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_pro2.0' into dev_pro2.0
---
ZSJC.bat | 451 ++++++++++++++++++++
src/views/mes/qc/iqc/index.vue | 25
src/views/mes/qc/ipqc/data.ts | 43 +
src/views/mes/qc/iqc/data.ts | 28 +
src/views/wls/returnissue/modules/form.vue | 2
company.config.ts | 6
src/views/wls/productissue/components/select.vue | 141 ++++++
src/views/wls/returnissue/modules/line-form.vue | 10
src/views/mes/qc/rqc/index.vue | 25
src/views/wls/returnissue/data.ts | 36
src/api/mes/wm/productissue/line/index.ts | 8
src/views/mes/qc/components/export-range-modal.vue | 89 ++++
src/views/hrm/leave/modules/form.vue | 6
src/views/wls/productissue/components/select-dialog.vue | 106 ++++
src/api/hrm/leave/index.ts | 20
src/views/hrm/leave/detail/approve/index.vue | 2
src/views/hrm/leave/data.ts | 15
src/views/wls/productissue/components/index.ts | 2
src/views/mes/qc/oqc/data.ts | 37 +
src/views/mes/qc/ipqc/index.vue | 25
src/views/wls/productissue/data.ts | 45 ++
src/views/mes/qc/oqc/index.vue | 25
src/api/mes/qc/template/item/index.ts | 28 +
src/views/wls/returnissue/modules/line-list.vue | 5
src/views/hrm/leave/index.vue | 50 ++
src/api/mes/wm/returnissue/line/index.ts | 1
src/views/mes/qc/rqc/data.ts | 37 +
27 files changed, 1,203 insertions(+), 65 deletions(-)
diff --git a/ZSJC.bat b/ZSJC.bat
new file mode 100644
index 0000000..355c255
--- /dev/null
+++ b/ZSJC.bat
@@ -0,0 +1,451 @@
+@echo off
+setlocal EnableExtensions EnableDelayedExpansion
+
+REM ============================================================
+REM Vue Frontend Deploy Script
+REM ============================================================
+
+REM =========================
+REM Configuration
+REM =========================
+
+set "COMPANY=ZSJC"
+
+set "REMOTE_USER=root"
+set "REMOTE_HOST=116.172.73.239"
+set "REMOTE_PORT=22"
+
+set "PASSWORD=ecs-QGY8ecs-QGY8"
+
+set "ZIP_FILE=dist.zip"
+set "REMOTE_DIR=/home/vue/dist"
+
+set "SSH_OPTS=-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=15 -o ServerAliveCountMax=3"
+
+set "RETRY_COUNT=3"
+
+set "SSHPASS_DIR=%~dp0bin"
+
+
+REM ============================================================
+REM Start
+REM ============================================================
+
+echo.
+echo ============================================================
+echo Vue Dist Auto Deploy
+echo ============================================================
+echo.
+echo Company : %COMPANY%
+echo Server : %REMOTE_USER%@%REMOTE_HOST%
+echo Port : %REMOTE_PORT%
+echo Remote Dir : %REMOTE_DIR%
+echo Package : %ZIP_FILE%
+echo.
+
+
+REM ============================================================
+REM Check sshpass
+REM ============================================================
+
+echo [1/7] Checking sshpass...
+
+if exist "%SSHPASS_DIR%\sshpass.exe" (
+ set "PATH=%SSHPASS_DIR%;%PATH%"
+)
+
+where sshpass >nul 2>&1
+
+if not errorlevel 1 (
+ echo [OK] sshpass found.
+ goto CHECK_PNPM
+)
+
+echo [WARN] sshpass not found.
+
+if not exist "%SSHPASS_DIR%" (
+ mkdir "%SSHPASS_DIR%" >nul 2>&1
+)
+
+if exist "%SSHPASS_DIR%\sshpass.exe" (
+ set "PATH=%SSHPASS_DIR%;%PATH%"
+ echo [OK] sshpass found.
+ goto CHECK_PNPM
+)
+
+echo [INFO] Downloading sshpass...
+
+powershell -NoProfile -ExecutionPolicy Bypass -Command "$url='https://github.com/xhcoding/sshpass-win32/releases/download/v1.0.3/sshpass.exe'; $out='%SSHPASS_DIR%\sshpass.exe'; Invoke-WebRequest -Uri $url -OutFile $out"
+
+if errorlevel 1 (
+ echo [ERROR] Failed to download sshpass.
+ echo [ERROR] Please install sshpass manually.
+ goto ERROR_EXIT
+)
+
+set "PATH=%SSHPASS_DIR%;%PATH%"
+
+echo [OK] sshpass installed.
+
+
+REM ============================================================
+REM Check pnpm
+REM ============================================================
+
+:CHECK_PNPM
+
+echo.
+echo [2/7] Checking pnpm...
+
+where pnpm >nul 2>&1
+
+if errorlevel 1 (
+ echo [ERROR] pnpm not found.
+ echo [HINT] npm install -g pnpm
+ goto ERROR_EXIT
+)
+
+call pnpm --version
+
+if errorlevel 1 (
+ echo [ERROR] pnpm execution failed.
+ goto ERROR_EXIT
+)
+
+
+REM ============================================================
+REM Check node
+REM ============================================================
+
+echo.
+echo [3/7] Checking Node.js...
+
+where node >nul 2>&1
+
+if errorlevel 1 (
+ echo [ERROR] Node.js not found.
+ goto ERROR_EXIT
+)
+
+call node --version
+
+if errorlevel 1 (
+ echo [ERROR] Node.js execution failed.
+ goto ERROR_EXIT
+)
+
+
+REM ============================================================
+REM Check node_modules
+REM ============================================================
+
+if not exist "node_modules" (
+ echo.
+ echo [INFO] node_modules not found.
+ echo [INFO] Running pnpm install...
+
+ call pnpm install
+
+ if errorlevel 1 (
+ echo [ERROR] pnpm install failed.
+ goto ERROR_EXIT
+ )
+
+ echo [OK] pnpm install completed.
+) else (
+ echo [OK] node_modules exists.
+)
+
+
+REM ============================================================
+REM Build
+REM ============================================================
+
+echo.
+echo [4/7] Building project...
+
+if exist "%ZIP_FILE%" (
+ echo.
+ echo [WARN] %ZIP_FILE% already exists.
+ set "REBUILD="
+ set /p "REBUILD=Rebuild? Y/N (default Y): "
+
+ if /I "!REBUILD!"=="N" (
+ echo [INFO] Skip build.
+ goto CHECK_ZIP
+ )
+)
+
+echo [INFO] Company: %COMPANY%
+echo [INFO] Command: pnpm run build
+echo.
+
+set "VITE_COMPANY=%COMPANY%"
+
+call pnpm run build
+
+if errorlevel 1 (
+ echo.
+ echo [ERROR] Build failed.
+ goto ERROR_EXIT
+)
+
+echo.
+echo [OK] Build completed.
+
+
+REM ============================================================
+REM Check ZIP
+REM ============================================================
+
+:CHECK_ZIP
+
+echo.
+echo [5/7] Checking package...
+
+if not exist "%ZIP_FILE%" (
+ echo [ERROR] %ZIP_FILE% not found.
+ echo [HINT] Please check whether your build generates dist.zip.
+ goto ERROR_EXIT
+)
+
+for %%F in ("%ZIP_FILE%") do set "ZIP_BYTES=%%~zF"
+
+set /a ZIP_MB=ZIP_BYTES/1024/1024
+
+echo [OK] Package found.
+echo [INFO] File size: !ZIP_BYTES! bytes
+echo [INFO] File size: !ZIP_MB! MB
+
+
+REM ============================================================
+REM Set sshpass password
+REM ============================================================
+
+set "SSHPASS=%PASSWORD%"
+
+
+REM ============================================================
+REM Test SSH
+REM ============================================================
+
+echo.
+echo [6/7] Testing SSH connection...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "echo SSH_OK"
+
+if errorlevel 1 (
+ echo [ERROR] SSH connection failed.
+ goto ERROR_EXIT
+)
+
+echo [OK] SSH connection successful.
+
+
+REM ============================================================
+REM Create remote directory
+REM ============================================================
+
+echo.
+echo [INFO] Creating remote directory...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "mkdir -p '%REMOTE_DIR%'"
+
+if errorlevel 1 (
+ echo [ERROR] Failed to create remote directory.
+ goto ERROR_EXIT
+)
+
+echo [OK] Remote directory ready.
+
+
+REM ============================================================
+REM Upload temporary file
+REM ============================================================
+
+echo.
+echo [INFO] Uploading package...
+
+set "REMOTE_TMP=%REMOTE_DIR%/.dist.zip.uploading"
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "rm -f '%REMOTE_TMP%'"
+
+sshpass -e scp -P %REMOTE_PORT% %SSH_OPTS% "%ZIP_FILE%" %REMOTE_USER%@%REMOTE_HOST%:"%REMOTE_TMP%"
+
+if errorlevel 1 (
+ echo [ERROR] Upload failed.
+ goto ERROR_EXIT
+)
+
+echo [OK] Upload completed.
+
+
+REM ============================================================
+REM Check remote file
+REM ============================================================
+
+echo.
+echo [INFO] Checking remote package...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "test -f '%REMOTE_TMP%'"
+
+if errorlevel 1 (
+ echo [ERROR] Remote package does not exist.
+ goto ERROR_EXIT
+)
+
+echo [OK] Remote package exists.
+
+
+REM ============================================================
+REM Compare file size
+REM ============================================================
+
+echo.
+echo [INFO] Checking package size...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "stat -c %%s '%REMOTE_TMP%'"
+
+echo.
+
+
+REM ============================================================
+REM Rename temporary file
+REM ============================================================
+
+echo [INFO] Activating package...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "mv -f '%REMOTE_TMP%' '%REMOTE_DIR%/%ZIP_FILE%'"
+
+if errorlevel 1 (
+ echo [ERROR] Failed to activate package.
+ goto ERROR_EXIT
+)
+
+echo [OK] Package activated.
+
+
+REM ============================================================
+REM Check unzip
+REM ============================================================
+
+echo.
+echo [INFO] Checking unzip...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "command -v unzip"
+
+if errorlevel 1 (
+ echo [ERROR] unzip is not installed on server.
+ echo.
+ echo CentOS/RHEL:
+ echo yum install -y unzip
+ echo.
+ echo Ubuntu/Debian:
+ echo apt install -y unzip
+ goto ERROR_EXIT
+)
+
+echo [OK] unzip found.
+
+
+REM ============================================================
+REM Test ZIP
+REM ============================================================
+
+echo.
+echo [INFO] Testing remote ZIP...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "cd '%REMOTE_DIR%' && unzip -t '%ZIP_FILE%'"
+
+if errorlevel 1 (
+ echo.
+ echo [ERROR] ZIP test failed.
+ echo [INFO] Remote ZIP has been kept.
+ goto ERROR_EXIT
+)
+
+echo [OK] ZIP test passed.
+
+
+REM ============================================================
+REM Extract
+REM ============================================================
+
+echo.
+echo [INFO] Extracting package...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "cd '%REMOTE_DIR%' && unzip -o '%ZIP_FILE%'"
+
+if errorlevel 1 (
+ echo.
+ echo [ERROR] Remote unzip failed.
+ echo [INFO] Remote ZIP has been kept.
+ goto ERROR_EXIT
+)
+
+echo.
+echo [OK] Extract completed.
+
+
+REM ============================================================
+REM Remove ZIP
+REM ============================================================
+
+echo.
+echo [INFO] Removing remote ZIP...
+
+sshpass -e ssh -p %REMOTE_PORT% %SSH_OPTS% %REMOTE_USER%@%REMOTE_HOST% "rm -f '%REMOTE_DIR%/%ZIP_FILE%'"
+
+if errorlevel 1 (
+ echo [WARN] Failed to remove remote ZIP.
+) else (
+ echo [OK] Remote ZIP removed.
+)
+
+
+REM ============================================================
+REM Success
+REM ============================================================
+
+echo.
+echo ============================================================
+echo DEPLOY SUCCESS
+echo ============================================================
+echo.
+echo Company : %COMPANY%
+echo Server : %REMOTE_HOST%:%REMOTE_PORT%
+echo Remote Dir : %REMOTE_DIR%
+echo Package : %ZIP_FILE%
+echo Size : !ZIP_MB! MB
+echo.
+echo Deployment completed successfully.
+echo.
+
+goto END
+
+
+REM ============================================================
+REM Error
+REM ============================================================
+
+:ERROR_EXIT
+
+echo.
+echo ============================================================
+echo DEPLOY FAILED
+echo ============================================================
+echo.
+echo Please check the error message above.
+echo.
+
+goto END
+
+
+REM ============================================================
+REM End
+REM ============================================================
+
+:END
+
+pause
+endlocal
\ No newline at end of file
diff --git a/company.config.ts b/company.config.ts
index 2256fd5..74029f4 100644
--- a/company.config.ts
+++ b/company.config.ts
@@ -53,4 +53,10 @@
favicon: '/logos/YZFXLogo.ico',
apiUrl: 'http://42.63.71.140:9004/admin-api',
},
+ ZSJC: {
+ name: '瀹佸涓洓寤烘潗绉戞妧鏈夐檺鍏徃',
+ logo: '/logos/YZFXLogo.png',
+ favicon: '/logos/YZFXLogo.ico',
+ apiUrl: 'http://116.172.73.239:9001/admin-api',
+ },
};
diff --git a/src/api/hrm/leave/index.ts b/src/api/hrm/leave/index.ts
index e280286..ee16a80 100644
--- a/src/api/hrm/leave/index.ts
+++ b/src/api/hrm/leave/index.ts
@@ -7,8 +7,8 @@
/** 璇峰亣鐢宠 */
export interface Leave {
id?: number;
- employeeId?: number;
- employeeName?: string;
+ userId?: number;
+ userName?: string;
deptName?: string;
leaveType?: number;
startTime?: string;
@@ -21,6 +21,12 @@
processInstanceId?: string;
remark?: string;
createTime?: string;
+ }
+
+ /** 瀹℃壒娴佺▼ */
+ export interface ApproveProcess {
+ key: string;
+ name: string;
}
}
@@ -53,8 +59,10 @@
}
/** 鎻愪氦璇峰亣鐢宠锛堝彂璧峰鎵癸級 */
-export function submitLeave(id: number) {
- return requestClient.post(`/hrm/leave/submit?id=${id}`);
+export function submitLeave(id: number, processDefinitionKey: string) {
+ return requestClient.post('/hrm/leave/submit', null, {
+ params: { id, processDefinitionKey },
+ });
}
/** 鎾ら攢璇峰亣鐢宠 */
@@ -64,5 +72,7 @@
/** 鑾峰彇鍙敤娴佺▼瀹氫箟鍒楄〃 */
export function getLeaveApproveProcessDefinitionList() {
- return requestClient.get<any[]>('/hrm/leave/approve-process-definition-list');
+ return requestClient.get<HrmLeaveApi.ApproveProcess[]>(
+ '/hrm/leave/approve-process-definition-list',
+ );
}
\ No newline at end of file
diff --git a/src/api/mes/qc/template/item/index.ts b/src/api/mes/qc/template/item/index.ts
index a7b92c1..d10c641 100644
--- a/src/api/mes/qc/template/item/index.ts
+++ b/src/api/mes/qc/template/item/index.ts
@@ -21,6 +21,21 @@
}
}
+/** 璐ㄦ鏂规閫夐」锛堟柟妗�-浜у搧鍏宠仈锛� */
+export namespace MesQcTemplateItemOptionApi {
+ export interface Option {
+ id?: number; // 浜у搧鍏宠仈缂栧彿
+ templateId?: number; // 璐ㄦ鏂规 ID
+ templateCode?: string; // 璐ㄦ鏂规缂栧彿
+ templateName?: string; // 璐ㄦ鏂规鍚嶇О
+ quantityCheck?: number; // 鏈�浣庢娴嬫暟
+ quantityUnqualified?: number; // 鏈�澶т笉鍚堟牸鏁�
+ criticalRate?: number; // 鏈�澶ц嚧鍛界己闄风巼锛�%锛�
+ majorRate?: number; // 鏈�澶т弗閲嶇己闄风巼锛�%锛�
+ minorRate?: number; // 鏈�澶ц交寰己闄风巼锛�%锛�
+ }
+}
+
/** 鏌ヨ浜у搧鍏宠仈鍒嗛〉 */
export function getTemplateItemPage(
params: PageParam & { templateId?: number },
@@ -52,3 +67,16 @@
export function deleteTemplateItem(id: number) {
return requestClient.delete(`/mes/qc/template/item/delete?id=${id}`);
}
+
+/** 鏍规嵁鐗╂枡鎴栧伐鍗�/浠诲姟鍜屾娴嬬绫昏幏鍙栧彲鐢ㄨ川妫�鏂规鍒楄〃 */
+export function getTemplateItemOptionList(params: {
+ itemId?: number;
+ qcType: number;
+ taskId?: number;
+ workOrderId?: number;
+}) {
+ return requestClient.get<MesQcTemplateItemOptionApi.Option[]>(
+ '/mes/qc/template/item/list-by-item-and-type',
+ { params },
+ );
+}
diff --git a/src/api/mes/wm/productissue/line/index.ts b/src/api/mes/wm/productissue/line/index.ts
index 285d37a..9b79b2f 100644
--- a/src/api/mes/wm/productissue/line/index.ts
+++ b/src/api/mes/wm/productissue/line/index.ts
@@ -69,3 +69,11 @@
{ params: { issueId } },
);
}
+
+/** 鏌ヨ鍙��鏂欑殑棰嗘枡鍗曡鍒楄〃锛堟寜鐢熶骇璁㈠崟杩囨护锛屼粎杩斿洖宸插畬鎴愰鏂欑殑璁板綍锛� */
+export function getReturnableIssueLines(workOrderId: number) {
+ return requestClient.get<MesWmProductIssueLineApi.ProductIssueLine[]>(
+ '/mes/wm/product-issue-line/returnable-list',
+ { params: { workOrderId } },
+ );
+}
diff --git a/src/api/mes/wm/returnissue/line/index.ts b/src/api/mes/wm/returnissue/line/index.ts
index 05bef07..d1bb469 100644
--- a/src/api/mes/wm/returnissue/line/index.ts
+++ b/src/api/mes/wm/returnissue/line/index.ts
@@ -7,6 +7,7 @@
export interface ReturnIssueLine {
id?: number; // 琛岀紪鍙�
issueId?: number; // 閫�鏂欏崟缂栧彿
+ issueLineId?: number; // 棰嗘枡鍗曡缂栧彿锛堝叧鑱旀潵婧愰鏂欒褰曪級
itemId?: number; // 鐗╂枡缂栧彿
itemCode?: string; // 鐗╂枡缂栫爜
itemName?: string; // 鐗╂枡鍚嶇О
diff --git a/src/views/hrm/leave/data.ts b/src/views/hrm/leave/data.ts
index c6d5154..6e8570e 100644
--- a/src/views/hrm/leave/data.ts
+++ b/src/views/hrm/leave/data.ts
@@ -2,8 +2,12 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { HrmLeaveApi } from '#/api/hrm/leave';
+import { markRaw } from 'vue';
+
import { DICT_TYPE } from '#/packages/constants/src';
import { getDictOptions } from '#/packages/effects/hooks/src';
+
+import { UserSelect } from '#/views/system/user/components';
/** 琛ㄥ崟绫诲瀷 */
export type FormType = 'create' | 'detail' | 'update';
@@ -18,6 +22,15 @@
triggerFields: [''],
show: () => false,
},
+ },
+ {
+ fieldName: 'userId',
+ label: '鐢宠浜�',
+ component: markRaw(UserSelect),
+ componentProps: {
+ placeholder: '璇烽�夋嫨鐢宠浜�',
+ },
+ rules: 'selectRequired',
},
{
fieldName: 'leaveType',
@@ -134,7 +147,7 @@
export function useGridColumns(): VxeTableGridOptions<HrmLeaveApi.Leave>['columns'] {
return [
{ field: 'id', title: '鐢宠缂栧彿', width: 80 },
- { field: 'employeeName', title: '鐢宠浜�', minWidth: 100 },
+ { field: 'userName', title: '鐢宠浜�', minWidth: 100 },
{ field: 'deptName', title: '閮ㄩ棬', minWidth: 120 },
{
field: 'leaveType',
diff --git a/src/views/hrm/leave/detail/approve/index.vue b/src/views/hrm/leave/detail/approve/index.vue
index 59248e4..0573837 100644
--- a/src/views/hrm/leave/detail/approve/index.vue
+++ b/src/views/hrm/leave/detail/approve/index.vue
@@ -30,7 +30,7 @@
bordered: true,
column: 2,
schema: [
- { label: '鍛樺伐濮撳悕', field: 'employeeName', render: textRender },
+ { label: '鐢宠浜�', field: 'userName', render: textRender },
{ label: '鎵�灞為儴闂�', field: 'deptName', render: textRender },
{
label: '璇峰亣绫诲瀷',
diff --git a/src/views/hrm/leave/index.vue b/src/views/hrm/leave/index.vue
index e7ae028..d088fc2 100644
--- a/src/views/hrm/leave/index.vue
+++ b/src/views/hrm/leave/index.vue
@@ -2,9 +2,11 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { HrmLeaveApi } from '#/api/hrm/leave';
+import { ref } from 'vue';
+
import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
-import { message, Tag } from 'ant-design-vue';
+import { message, Modal, Select, Tag } from 'ant-design-vue';
import { DICT_TYPE } from '#/packages/constants/src';
import { getDictLabel } from '#/packages/effects/hooks/src';
@@ -13,6 +15,7 @@
import {
cancelLeave,
deleteLeave,
+ getLeaveApproveProcessDefinitionList,
getLeavePage,
submitLeave,
} from '#/api/hrm/leave';
@@ -61,11 +64,34 @@
}
}
-/** 鎻愪氦璇峰亣鐢宠 */
+const submitModalVisible = ref(false);
+const currentRow = ref<HrmLeaveApi.Leave>();
+const processList = ref<HrmLeaveApi.ApproveProcess[]>([]);
+const selectedProcessKey = ref<string>();
+const submitLoading = ref(false);
+
+/** 鎻愪氦璇峰亣鐢宠锛堝厛閫夋嫨瀹℃壒娴佺▼锛� */
async function handleSubmit(row: HrmLeaveApi.Leave) {
- await submitLeave(row.id!);
- message.success('鎻愪氦鎴愬姛');
- handleRefresh();
+ processList.value = await getLeaveApproveProcessDefinitionList();
+ currentRow.value = row;
+ selectedProcessKey.value = undefined;
+ submitModalVisible.value = true;
+}
+
+async function confirmSubmit() {
+ if (!selectedProcessKey.value) {
+ message.warning('璇烽�夋嫨璇峰亣瀹℃壒娴佺▼');
+ return;
+ }
+ submitLoading.value = true;
+ try {
+ await submitLeave(currentRow.value!.id!, selectedProcessKey.value);
+ message.success('鎻愪氦鎴愬姛');
+ submitModalVisible.value = false;
+ handleRefresh();
+ } finally {
+ submitLoading.value = false;
+ }
}
/** 鎾ら攢璇峰亣鐢宠 */
@@ -187,5 +213,19 @@
/>
</template>
</Grid>
+ <Modal
+ v-model:open="submitModalVisible"
+ title="鎻愪氦鑷冲崗鍚屽姙鍏�"
+ width="420px"
+ :confirm-loading="submitLoading"
+ @ok="confirmSubmit"
+ >
+ <Select
+ v-model:value="selectedProcessKey"
+ class="w-full"
+ placeholder="璇烽�夋嫨璇峰亣瀹℃壒娴佺▼"
+ :options="processList.map((item) => ({ label: item.name, value: item.key }))"
+ />
+ </Modal>
</Page>
</template>
\ No newline at end of file
diff --git a/src/views/hrm/leave/modules/form.vue b/src/views/hrm/leave/modules/form.vue
index 4aab581..f701b81 100644
--- a/src/views/hrm/leave/modules/form.vue
+++ b/src/views/hrm/leave/modules/form.vue
@@ -4,6 +4,8 @@
import { computed, ref } from 'vue';
+import { useUserStore } from '@vben/stores';
+
import { useVbenModal } from '#/packages/effects/common-ui/src';
import { message } from 'ant-design-vue';
@@ -16,6 +18,8 @@
const emit = defineEmits(['success']);
const formType = ref<FormType>('create');
+
+const userStore = useUserStore();
const isDetail = computed(() => formType.value === 'detail');
const getTitle = computed(() => {
@@ -74,6 +78,8 @@
formApi.setDisabled(data.formType === 'detail');
modalApi.setState({ showConfirmButton: data.formType !== 'detail' });
if (!data?.id) {
+ // 鏂板鏃堕粯璁ょ敵璇蜂汉涓哄綋鍓嶇櫥褰曠敤鎴凤紝鍙慨鏀�
+ await formApi.setFieldValue('userId', userStore.userInfo?.id);
return;
}
modalApi.lock();
diff --git a/src/views/mes/qc/components/export-range-modal.vue b/src/views/mes/qc/components/export-range-modal.vue
new file mode 100644
index 0000000..19fedfe
--- /dev/null
+++ b/src/views/mes/qc/components/export-range-modal.vue
@@ -0,0 +1,89 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { downloadFileFromBlobPart } from '@vben/utils';
+
+import { DatePicker, message } from 'ant-design-vue';
+
+import { getRangePickerDefaultProps } from '#/utils';
+
+/** 瀵煎嚭鍙傛暟锛堝悗绔� PageReqVO 浠ユ暟缁勮В鏋� inspectDate 璧锋锛� */
+interface ExportParams {
+ inspectDate?: [string, string];
+}
+
+interface ExportModalData {
+ /** 寮圭獥鏍囬 */
+ title?: string;
+ /** 妯″潡瀵煎嚭鍑芥暟锛歳equestClient.download(...) 杩斿洖 Blob */
+ exportApi: (params: ExportParams) => Promise<Blob>;
+ /** 瀵煎嚭鏂囦欢鍚� */
+ fileName: string;
+}
+
+defineOptions({ name: 'QcExportRangeModal' });
+
+const rangePickerProps = getRangePickerDefaultProps();
+
+const modalData = ref<ExportModalData>();
+const range = ref<[string, string] | undefined>(undefined);
+const exporting = ref(false);
+const title = ref('瀵煎嚭');
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ if (exporting.value) {
+ return;
+ }
+ const data = modalData.value;
+ if (!data) {
+ return;
+ }
+ exporting.value = true;
+ modalApi.lock();
+ try {
+ const params: ExportParams =
+ range.value && range.value.length === 2
+ ? { inspectDate: range.value }
+ : {};
+ const blob = await data.exportApi(params);
+ downloadFileFromBlobPart({ fileName: data.fileName, source: blob });
+ message.success('瀵煎嚭鎴愬姛');
+ await modalApi.close();
+ } finally {
+ exporting.value = false;
+ modalApi.unlock();
+ }
+ },
+ onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ modalData.value = undefined;
+ range.value = undefined;
+ return;
+ }
+ const data = modalApi.getData<ExportModalData>();
+ modalData.value = data;
+ range.value = undefined;
+ title.value = data?.title ?? '瀵煎嚭';
+ modalApi.setState({ confirmText: '瀵煎嚭' });
+ },
+});
+</script>
+
+<template>
+ <Modal :title="title" class="w-2/5" :mask-closable="false">
+ <div class="px-1 py-3">
+ <div class="mb-2 text-sm font-medium text-gray-700">妫�楠屾椂闂�</div>
+ <DatePicker.RangePicker
+ v-model:value="range"
+ v-bind="rangePickerProps"
+ allow-clear
+ class="w-full"
+ />
+ <div class="mt-2 text-xs text-gray-400">
+ 涓嶉�夋椂闂村垯瀵煎嚭鍏ㄩ儴鏁版嵁锛涘鍑烘寜銆屾娴嬫棩鏈熴�嶈繃婊�
+ </div>
+ </div>
+ </Modal>
+</template>
diff --git a/src/views/mes/qc/ipqc/data.ts b/src/views/mes/qc/ipqc/data.ts
index 58f1e88..86522b9 100644
--- a/src/views/mes/qc/ipqc/data.ts
+++ b/src/views/mes/qc/ipqc/data.ts
@@ -16,7 +16,9 @@
import { Button } from 'ant-design-vue';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
+import { getTemplateItemOptionList } from '#/api/mes/qc/template/item';
import { getSimpleUserList } from '#/api/system/user';
+import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
import { ProTaskSelect } from '#/views/mes/pro/task/components';
@@ -202,6 +204,39 @@
statuses: [MesProTaskStatusEnum.PREPARE],
workOrderId: values.workOrderId,
workstationId: values.workstationId,
+ }),
+ },
+ },
+ {
+ fieldName: 'templateId',
+ label: '璐ㄦ鏂规',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ placeholder: '璇烽�夋嫨璐ㄦ鏂规',
+ },
+ rules: 'selectRequired',
+ dependencies: {
+ triggerFields: ['workOrderId', 'taskId'],
+ componentProps: (values) => ({
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ disabled: formType !== 'create' || !values.workOrderId,
+ params: values.workOrderId
+ ? {
+ qcType: 2,
+ workOrderId: values.workOrderId,
+ taskId: values.taskId,
+ }
+ : {},
+ placeholder: values.workOrderId
+ ? '璇烽�夋嫨璐ㄦ鏂规'
+ : '璇峰厛閫夋嫨鐢熶骇璁㈠崟',
}),
},
},
@@ -404,6 +439,14 @@
placeholder: '璇烽�夋嫨妫�娴嬬粨鏋�',
},
},
+ {
+ fieldName: 'inspectDate',
+ label: '妫�娴嬫棩鏈�',
+ component: 'RangePicker',
+ componentProps: {
+ ...getRangePickerDefaultProps(),
+ },
+ },
];
}
diff --git a/src/views/mes/qc/ipqc/index.vue b/src/views/mes/qc/ipqc/index.vue
index 32d46c4..832a85a 100644
--- a/src/views/mes/qc/ipqc/index.vue
+++ b/src/views/mes/qc/ipqc/index.vue
@@ -4,19 +4,24 @@
import { Page, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum } from '@vben/constants';
-import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteIpqc, exportIpqc, getIpqcPage } from '#/api/mes/qc/ipqc';
import { $t } from '#/locales';
+import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
+ destroyOnClose: true,
+});
+
+const [ExportRangeModal, exportRangeModalApi] = useVbenModal({
+ connectedComponent: QcExportRangeModal,
destroyOnClose: true,
});
@@ -55,10 +60,15 @@
}
}
-/** 瀵煎嚭琛ㄦ牸 */
-async function handleExport() {
- const data = await exportIpqc(await gridApi.formApi.getValues());
- downloadFileFromBlobPart({ fileName: '杩囩▼妫�楠屽崟.xls', source: data });
+/** 瀵煎嚭琛ㄦ牸锛堝脊绐楅�夋楠屾椂闂磋寖鍥达級 */
+function handleExport() {
+ exportRangeModalApi
+ .setData({
+ title: '鎸夋楠屾椂闂村鍑鸿繃绋嬫楠屽崟',
+ exportApi: exportIpqc,
+ fileName: '杩囩▼妫�楠屽崟.xls',
+ })
+ .open();
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -93,8 +103,9 @@
</script>
<template>
- <Page auto-content-height><FormModal @success="handleRefresh" />
-
+ <Page auto-content-height>
+ <FormModal @success="handleRefresh" />
+ <ExportRangeModal />
<Grid table-title="杩囩▼妫�楠屽崟鍒楄〃">
<template #toolbar-tools>
<TableAction
diff --git a/src/views/mes/qc/iqc/data.ts b/src/views/mes/qc/iqc/data.ts
index 40cb523..a59f777 100644
--- a/src/views/mes/qc/iqc/data.ts
+++ b/src/views/mes/qc/iqc/data.ts
@@ -11,6 +11,7 @@
import { Button } from 'ant-design-vue';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
+import { getTemplateItemOptionList } from '#/api/mes/qc/template/item';
import { getSupplierSimpleList } from '#/api/srm/supplier';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
@@ -135,6 +136,33 @@
},
},
{
+ fieldName: 'templateId',
+ label: '璐ㄦ鏂规',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ placeholder: '璇烽�夋嫨璐ㄦ鏂规',
+ },
+ rules: 'selectRequired',
+ dependencies: {
+ triggerFields: ['itemId'],
+ componentProps: (values) => ({
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ disabled: formType !== 'create' || !values.itemId,
+ params: values.itemId
+ ? { itemId: values.itemId, qcType: 1 }
+ : {},
+ placeholder: values.itemId ? '璇烽�夋嫨璐ㄦ鏂规' : '璇峰厛閫夋嫨浜у搧鐗╂枡',
+ }),
+ },
+ },
+ {
fieldName: 'vendorId',
label: '渚涘簲鍟�',
component: 'ApiSelect',
diff --git a/src/views/mes/qc/iqc/index.vue b/src/views/mes/qc/iqc/index.vue
index 44e0901..761305f 100644
--- a/src/views/mes/qc/iqc/index.vue
+++ b/src/views/mes/qc/iqc/index.vue
@@ -7,13 +7,13 @@
import { Page, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum } from '@vben/constants';
-import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteIqc, exportIqc, getIqcPage } from '#/api/mes/qc/iqc';
import { $t } from '#/locales';
+import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
@@ -24,6 +24,11 @@
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
+ destroyOnClose: true,
+});
+
+const [ExportRangeModal, exportRangeModalApi] = useVbenModal({
+ connectedComponent: QcExportRangeModal,
destroyOnClose: true,
});
@@ -62,10 +67,15 @@
}
}
-/** 瀵煎嚭琛ㄦ牸 */
-async function handleExport() {
- const data = await exportIqc(await gridApi.formApi.getValues());
- downloadFileFromBlobPart({ fileName: '鏉ユ枡妫�楠屽崟.xls', source: data });
+/** 瀵煎嚭琛ㄦ牸锛堝脊绐楅�夋楠屾椂闂磋寖鍥达級 */
+function handleExport() {
+ exportRangeModalApi
+ .setData({
+ title: '鎸夋楠屾椂闂村鍑烘潵鏂欐楠屽崟',
+ exportApi: exportIqc,
+ fileName: '鏉ユ枡妫�楠屽崟.xls',
+ })
+ .open();
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -107,8 +117,9 @@
</script>
<template>
- <Page auto-content-height><FormModal @success="handleRefresh" />
-
+ <Page auto-content-height>
+ <FormModal @success="handleRefresh" />
+ <ExportRangeModal />
<Grid table-title="鏉ユ枡妫�楠屽崟鍒楄〃">
<template #toolbar-tools>
<TableAction
diff --git a/src/views/mes/qc/oqc/data.ts b/src/views/mes/qc/oqc/data.ts
index 0183a35..54b6766 100644
--- a/src/views/mes/qc/oqc/data.ts
+++ b/src/views/mes/qc/oqc/data.ts
@@ -11,7 +11,9 @@
import { Button } from 'ant-design-vue';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
+import { getTemplateItemOptionList } from '#/api/mes/qc/template/item';
import { getSimpleUserList } from '#/api/system/user';
+import { getRangePickerDefaultProps } from '#/utils';
import CrmCustomerSelect from '#/components/crm-customer-select.vue';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
@@ -129,6 +131,33 @@
componentProps: (values) => ({
disabled: !!values.sourceDocId,
placeholder: '璇烽�夋嫨浜у搧鐗╂枡',
+ }),
+ },
+ },
+ {
+ fieldName: 'templateId',
+ label: '璐ㄦ鏂规',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ placeholder: '璇烽�夋嫨璐ㄦ鏂规',
+ },
+ rules: 'selectRequired',
+ dependencies: {
+ triggerFields: ['itemId'],
+ componentProps: (values) => ({
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ disabled: formType !== 'create' || !values.itemId,
+ params: values.itemId
+ ? { itemId: values.itemId, qcType: 3 }
+ : {},
+ placeholder: values.itemId ? '璇烽�夋嫨璐ㄦ鏂规' : '璇峰厛閫夋嫨浜у搧鐗╂枡',
}),
},
},
@@ -340,6 +369,14 @@
placeholder: '璇烽�夋嫨妫�娴嬬粨鏋�',
},
},
+ {
+ fieldName: 'inspectDate',
+ label: '妫�娴嬫棩鏈�',
+ component: 'RangePicker',
+ componentProps: {
+ ...getRangePickerDefaultProps(),
+ },
+ },
];
}
diff --git a/src/views/mes/qc/oqc/index.vue b/src/views/mes/qc/oqc/index.vue
index 965cfda..f9043b1 100644
--- a/src/views/mes/qc/oqc/index.vue
+++ b/src/views/mes/qc/oqc/index.vue
@@ -4,19 +4,24 @@
import { Page, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum } from '@vben/constants';
-import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteOqc, exportOqc, getOqcPage } from '#/api/mes/qc/oqc';
import { $t } from '#/locales';
+import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
+ destroyOnClose: true,
+});
+
+const [ExportRangeModal, exportRangeModalApi] = useVbenModal({
+ connectedComponent: QcExportRangeModal,
destroyOnClose: true,
});
@@ -55,10 +60,15 @@
}
}
-/** 瀵煎嚭琛ㄦ牸 */
-async function handleExport() {
- const data = await exportOqc(await gridApi.formApi.getValues());
- downloadFileFromBlobPart({ fileName: '鍑鸿揣妫�楠屽崟.xls', source: data });
+/** 瀵煎嚭琛ㄦ牸锛堝脊绐楅�夋楠屾椂闂磋寖鍥达級 */
+function handleExport() {
+ exportRangeModalApi
+ .setData({
+ title: '鎸夋楠屾椂闂村鍑鸿揣妫�楠屽崟',
+ exportApi: exportOqc,
+ fileName: '鍑鸿揣妫�楠屽崟.xls',
+ })
+ .open();
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -93,8 +103,9 @@
</script>
<template>
- <Page auto-content-height><FormModal @success="handleRefresh" />
-
+ <Page auto-content-height>
+ <FormModal @success="handleRefresh" />
+ <ExportRangeModal />
<Grid table-title="鍑鸿揣妫�楠屽崟鍒楄〃">
<template #toolbar-tools>
<TableAction
diff --git a/src/views/mes/qc/rqc/data.ts b/src/views/mes/qc/rqc/data.ts
index 92d5e1e..ab9af37 100644
--- a/src/views/mes/qc/rqc/data.ts
+++ b/src/views/mes/qc/rqc/data.ts
@@ -15,7 +15,9 @@
import { Button } from 'ant-design-vue';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
+import { getTemplateItemOptionList } from '#/api/mes/qc/template/item';
import { getSimpleUserList } from '#/api/system/user';
+import { getRangePickerDefaultProps } from '#/utils';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
/** 琛ㄥ崟绫诲瀷 */
@@ -154,6 +156,33 @@
componentProps: (values) => ({
disabled: !!values.sourceDocId,
placeholder: '璇烽�夋嫨浜у搧鐗╂枡',
+ }),
+ },
+ },
+ {
+ fieldName: 'templateId',
+ label: '璐ㄦ鏂规',
+ component: 'ApiSelect',
+ componentProps: {
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ placeholder: '璇烽�夋嫨璐ㄦ鏂规',
+ },
+ rules: 'selectRequired',
+ dependencies: {
+ triggerFields: ['itemId'],
+ componentProps: (values) => ({
+ api: getTemplateItemOptionList,
+ autoSelect: 'first',
+ labelField: 'templateName',
+ valueField: 'templateId',
+ disabled: formType !== 'create' || !values.itemId,
+ params: values.itemId
+ ? { itemId: values.itemId, qcType: 4 }
+ : {},
+ placeholder: values.itemId ? '璇烽�夋嫨璐ㄦ鏂规' : '璇峰厛閫夋嫨浜у搧鐗╂枡',
}),
},
},
@@ -330,6 +359,14 @@
valueField: 'id',
},
},
+ {
+ fieldName: 'inspectDate',
+ label: '妫�娴嬫棩鏈�',
+ component: 'RangePicker',
+ componentProps: {
+ ...getRangePickerDefaultProps(),
+ },
+ },
];
}
diff --git a/src/views/mes/qc/rqc/index.vue b/src/views/mes/qc/rqc/index.vue
index 0cfc6f2..2771b4c 100644
--- a/src/views/mes/qc/rqc/index.vue
+++ b/src/views/mes/qc/rqc/index.vue
@@ -4,19 +4,24 @@
import { Page, useVbenModal } from '@vben/common-ui';
import { MesQcStatusEnum } from '@vben/constants';
-import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteRqc, exportRqc, getRqcPage } from '#/api/mes/qc/rqc';
import { $t } from '#/locales';
+import QcExportRangeModal from '#/views/mes/qc/components/export-range-modal.vue';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
+ destroyOnClose: true,
+});
+
+const [ExportRangeModal, exportRangeModalApi] = useVbenModal({
+ connectedComponent: QcExportRangeModal,
destroyOnClose: true,
});
@@ -55,10 +60,15 @@
}
}
-/** 瀵煎嚭琛ㄦ牸 */
-async function handleExport() {
- const data = await exportRqc(await gridApi.formApi.getValues());
- downloadFileFromBlobPart({ fileName: '閫�璐ф楠屽崟.xls', source: data });
+/** 瀵煎嚭琛ㄦ牸锛堝脊绐楅�夋楠屾椂闂磋寖鍥达級 */
+function handleExport() {
+ exportRangeModalApi
+ .setData({
+ title: '鎸夋楠屾椂闂村閫�璐ф楠屽崟',
+ exportApi: exportRqc,
+ fileName: '閫�璐ф楠屽崟.xls',
+ })
+ .open();
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -93,8 +103,9 @@
</script>
<template>
- <Page auto-content-height><FormModal @success="handleRefresh" />
-
+ <Page auto-content-height>
+ <FormModal @success="handleRefresh" />
+ <ExportRangeModal />
<Grid table-title="閫�璐ф楠屽崟鍒楄〃">
<template #toolbar-tools>
<TableAction
diff --git a/src/views/wls/productissue/components/index.ts b/src/views/wls/productissue/components/index.ts
new file mode 100644
index 0000000..aa8b15e
--- /dev/null
+++ b/src/views/wls/productissue/components/index.ts
@@ -0,0 +1,2 @@
+export { default as WmProductIssueLineSelect } from './select.vue';
+export { default as WmProductIssueLineSelectDialog } from './select-dialog.vue';
diff --git a/src/views/wls/productissue/components/select-dialog.vue b/src/views/wls/productissue/components/select-dialog.vue
new file mode 100644
index 0000000..09bb732
--- /dev/null
+++ b/src/views/wls/productissue/components/select-dialog.vue
@@ -0,0 +1,106 @@
+<script lang="ts" setup>
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line';
+
+import { nextTick, ref } from 'vue';
+
+import { message, Modal } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getReturnableIssueLines } from '#/api/mes/wm/productissue/line';
+
+const props = defineProps<{
+ workOrderId?: number;
+}>();
+
+const emit = defineEmits<{
+ selected: [rows: MesWmProductIssueLineApi.ProductIssueLine[]];
+}>();
+
+const open = ref(false);
+const selectedRows = ref<MesWmProductIssueLineApi.ProductIssueLine[]>([]);
+
+const columns: VxeTableGridOptions<MesWmProductIssueLineApi.ProductIssueLine>['columns'] = [
+ { type: 'radio', width: 60 },
+ { field: 'itemCode', title: '鐗╂枡缂栫爜', minWidth: 120 },
+ { field: 'itemName', title: '鐗╂枡鍚嶇О', minWidth: 140 },
+ { field: 'specification', title: '瑙勬牸鍨嬪彿', minWidth: 120 },
+ { field: 'unitMeasureName', title: '鍗曚綅', width: 80 },
+ { field: 'quantity', title: '鍙��鏁伴噺', width: 100 },
+ { field: 'batchCode', title: '鎵规鍙�', minWidth: 120 },
+];
+
+const [Grid, gridApi] = useVbenVxeGrid({
+ gridOptions: {
+ columns,
+ height: 480,
+ keepSource: true,
+ radioConfig: { highlight: true, trigger: 'row' },
+ proxyConfig: {
+ ajax: {
+ query: async () => {
+ if (!props.workOrderId) {
+ return { list: [], total: 0 };
+ }
+ const list = await getReturnableIssueLines(props.workOrderId);
+ return { list, total: list.length };
+ },
+ },
+ },
+ rowConfig: {
+ keyField: 'id',
+ isHover: true,
+ },
+ toolbarConfig: {
+ refresh: true,
+ },
+ } as VxeTableGridOptions<MesWmProductIssueLineApi.ProductIssueLine>,
+ gridEvents: {
+ radioChange: ({ row }: { row: MesWmProductIssueLineApi.ProductIssueLine }) => {
+ selectedRows.value = [row];
+ },
+ cellDblclick: async ({ row }: { row: MesWmProductIssueLineApi.ProductIssueLine }) => {
+ selectedRows.value = [row];
+ await gridApi.grid.setRadioRow(row);
+ handleConfirm();
+ },
+ },
+});
+
+async function openModal() {
+ open.value = true;
+ selectedRows.value = [];
+ await nextTick();
+ await gridApi.grid.clearRadioRow();
+ await gridApi.query();
+}
+
+function closeModal() {
+ open.value = false;
+ selectedRows.value = [];
+}
+
+function handleConfirm() {
+ if (selectedRows.value.length === 0) {
+ message.warning('璇烽�夋嫨涓�鏉¢鏂欒褰�');
+ return;
+ }
+ emit('selected', selectedRows.value);
+ open.value = false;
+}
+
+defineExpose({ open: openModal });
+</script>
+
+<template>
+ <Modal
+ v-model:open="open"
+ :destroy-on-close="true"
+ title="閫夋嫨棰嗘枡璁板綍"
+ width="70%"
+ @cancel="closeModal"
+ @ok="handleConfirm"
+ >
+ <Grid table-title="鍙��鏂欑殑棰嗘枡璁板綍" />
+ </Modal>
+</template>
diff --git a/src/views/wls/productissue/components/select.vue b/src/views/wls/productissue/components/select.vue
new file mode 100644
index 0000000..8a86b5f
--- /dev/null
+++ b/src/views/wls/productissue/components/select.vue
@@ -0,0 +1,141 @@
+<script lang="ts" setup>
+import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line';
+
+import { computed, ref, useAttrs, watch } from 'vue';
+
+import { IconifyIcon } from '@vben/icons';
+
+import { Input, Tooltip } from 'ant-design-vue';
+
+import { getProductIssueLine } from '#/api/mes/wm/productissue/line';
+
+import ProductIssueLineSelectDialog from './select-dialog.vue';
+
+defineOptions({ name: 'WmProductIssueLineSelect', inheritAttrs: false });
+
+const props = withDefaults(
+ defineProps<{
+ allowClear?: boolean;
+ disabled?: boolean;
+ modelValue?: number;
+ placeholder?: string;
+ workOrderId?: number;
+ }>(),
+ {
+ allowClear: true,
+ disabled: false,
+ modelValue: undefined,
+ placeholder: '璇烽�夋嫨棰嗘枡璁板綍',
+ workOrderId: undefined,
+ },
+);
+
+const emit = defineEmits<{
+ change: [item: MesWmProductIssueLineApi.ProductIssueLine | undefined];
+ 'update:modelValue': [value: number | undefined];
+}>();
+
+const attrs = useAttrs();
+const dialogRef = ref<InstanceType<typeof ProductIssueLineSelectDialog>>();
+const hovering = ref(false);
+const selectedItem = ref<MesWmProductIssueLineApi.ProductIssueLine>();
+
+const displayLabel = computed(() => {
+ const item = selectedItem.value;
+ if (!item) {
+ return '';
+ }
+ return `${item.itemCode || '-'} | ${item.itemName || '-'} | 鏁伴噺:${item.quantity}`;
+});
+
+const showClear = computed(
+ () =>
+ props.allowClear &&
+ !props.disabled &&
+ hovering.value &&
+ props.modelValue !== null,
+);
+
+async function resolveItemById(id: number | undefined) {
+ if (!id) {
+ selectedItem.value = undefined;
+ return;
+ }
+ if (selectedItem.value?.id === id) {
+ return;
+ }
+ selectedItem.value = await getProductIssueLine(id);
+}
+
+watch(() => props.modelValue, resolveItemById, { immediate: true });
+
+function clearSelected() {
+ selectedItem.value = undefined;
+ emit('update:modelValue', undefined);
+ emit('change', undefined);
+}
+
+function handleClick(event: MouseEvent) {
+ if (props.disabled) {
+ return;
+ }
+ const target = event.target as HTMLElement;
+ if (showClear.value && target.closest('.ant-input-suffix')) {
+ event.stopPropagation();
+ clearSelected();
+ return;
+ }
+ dialogRef.value?.open();
+}
+
+function handleSelected(rows: MesWmProductIssueLineApi.ProductIssueLine[]) {
+ const item = rows[0];
+ if (!item) {
+ return;
+ }
+ selectedItem.value = item;
+ emit('update:modelValue', item.id);
+ emit('change', item);
+}
+</script>
+
+<template>
+ <div
+ v-bind="attrs"
+ class="w-full"
+ :class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
+ @click="handleClick"
+ @mouseenter="hovering = true"
+ @mouseleave="hovering = false"
+ >
+ <Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false">
+ <template #title>
+ <div v-if="selectedItem" class="leading-6">
+ <div>鐗╂枡缂栫爜锛歿{ selectedItem.itemCode || '-' }}</div>
+ <div>鐗╂枡鍚嶇О锛歿{ selectedItem.itemName || '-' }}</div>
+ <div>瑙勬牸鍨嬪彿锛歿{ selectedItem.specification || '-' }}</div>
+ <div>鍙��鏁伴噺锛歿{ selectedItem.quantity ?? '-' }}</div>
+ <div>鎵规鍙凤細{{ selectedItem.batchCode || '-' }}</div>
+ </div>
+ </template>
+ <Input
+ :disabled="disabled"
+ :placeholder="placeholder"
+ :value="displayLabel"
+ readonly
+ >
+ <template #suffix>
+ <IconifyIcon
+ class="size-4"
+ :icon="showClear ? 'lucide:circle-x' : 'lucide:search'"
+ />
+ </template>
+ </Input>
+ </Tooltip>
+ </div>
+ <ProductIssueLineSelectDialog
+ ref="dialogRef"
+ :work-order-id="workOrderId"
+ @selected="handleSelected"
+ />
+</template>
diff --git a/src/views/wls/productissue/data.ts b/src/views/wls/productissue/data.ts
index 2ee6dcc..896c624 100644
--- a/src/views/wls/productissue/data.ts
+++ b/src/views/wls/productissue/data.ts
@@ -1,5 +1,6 @@
锘縤mport type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { MesProTaskApi } from '#/api/mes/pro/task';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
import type { MesWmProductIssueApi } from '#/api/mes/wm/productissue';
import type { MesWmProductIssueDetailApi } from '#/api/mes/wm/productissue/detail';
@@ -20,6 +21,7 @@
import { getRangePickerDefaultProps } from '#/utils';
import { MdItemSelect } from '#/views/mes/md/item/components';
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
+import { ProTaskSelect } from '#/views/mes/pro/task/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
import {
@@ -110,7 +112,33 @@
label: '鐢熶骇璁㈠崟',
component: markRaw(ProWorkOrderSelect),
componentProps: {
+ placeholder: '璇烽�夋嫨鐢熶骇璁㈠崟',
status: MesProWorkOrderStatusEnum.CONFIRMED,
+ // 璁㈠崟鍙樻洿锛氭竻绌哄凡閫夌敓浜т换鍔★紝閬垮厤浠诲姟涓庤鍗曚笉涓�鑷�
+ onChange: async () => {
+ await formApi?.setFieldValue('taskId', undefined);
+ },
+ },
+ rules: 'selectRequired',
+ },
+ {
+ fieldName: 'taskId',
+ label: '鐢熶骇浠诲姟',
+ component: markRaw(ProTaskSelect),
+ componentProps: {
+ placeholder: '璇烽�夋嫨鐢熶骇浠诲姟',
+ // 閫変腑浠诲姟鍚庤嚜鍔ㄥ甫鍑哄叾宸ヤ綔绔�
+ onChange: async (task?: MesProTaskApi.Task) => {
+ await formApi?.setFieldValue('workstationId', task?.workstationId);
+ },
+ },
+ dependencies: {
+ triggerFields: ['workOrderId'],
+ componentProps: (values) => ({
+ disabled: !values.workOrderId,
+ placeholder: values.workOrderId ? '璇烽�夋嫨鐢熶骇浠诲姟' : '璇峰厛閫夋嫨鐢熶骇璁㈠崟',
+ workOrderId: values.workOrderId,
+ }),
},
rules: 'selectRequired',
},
@@ -198,6 +226,11 @@
{
field: 'workOrderCode',
title: '鐢熶骇璁㈠崟',
+ minWidth: 140,
+ },
+ {
+ field: 'taskCode',
+ title: '鐢熶骇浠诲姟',
minWidth: 140,
},
{
@@ -370,6 +403,14 @@
},
},
{
+ fieldName: 'batchId',
+ component: 'Input',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+ {
fieldName: 'itemId',
label: '鐗╂枡',
component: markRaw(MdItemSelect),
@@ -382,12 +423,13 @@
label: '搴撳瓨璁板綍',
component: markRaw(WmMaterialStockSelect),
componentProps: {
- // 閫夋嫨搴撳瓨璁板綍鍚庯紝鑷姩鍥炲~浠撳簱/搴撳尯/搴撲綅/鎵规/鏁伴噺
+ // 閫夋嫨搴撳瓨璁板綍鍚庯紝鑷姩鍥炲~鐗╂枡/浠撳簱/搴撳尯/搴撲綅/鎵规/鏁伴噺锛屽叏閮ㄤ互搴撳瓨璁板綍涓哄噯
onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => {
await formApi?.setValues({
areaId: stock?.areaId,
batchCode: stock?.batchCode,
batchId: stock?.batchId,
+ itemId: stock?.itemId,
locationId: stock?.locationId,
quantity: stock?.quantity,
quantityMax: stock?.quantity,
@@ -399,6 +441,7 @@
dependencies: {
triggerFields: ['itemId'],
componentProps: (values) => ({
+ // 搴撳瓨閫夋嫨寮圭獥鍙瘑鍒� mdmItemId 鍏ュ弬锛屽苟鐢ㄥ畠浣滀负 itemId 杩囨护鏉′欢
mdmItemId: values.itemId,
}),
},
diff --git a/src/views/wls/returnissue/data.ts b/src/views/wls/returnissue/data.ts
index 4ca6336..691b573 100644
--- a/src/views/wls/returnissue/data.ts
+++ b/src/views/wls/returnissue/data.ts
@@ -1,6 +1,7 @@
锘縤mport type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
+import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line';
import type { MesWmReturnIssueApi } from '#/api/mes/wm/returnissue';
import type { MesWmReturnIssueDetailApi } from '#/api/mes/wm/returnissue/detail';
import type { MesWmReturnIssueLineApi } from '#/api/mes/wm/returnissue/line';
@@ -20,6 +21,7 @@
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
+import { WmProductIssueLineSelect } from '#/views/wls/productissue/components';
import { WmMaterialStockSelect } from '#/views/wls/materialstock/components';
import {
WmWarehouseAreaSelect,
@@ -316,27 +318,29 @@
}
/** 閫�鏂欏崟琛屾柊澧�/淇敼鐨勮〃鍗� */
-export function useLineFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
+export function useLineFormSchema(
+ formApi?: VbenFormApi,
+ workOrderId?: number,
+): VbenFormSchema[] {
return [
{
- fieldName: 'materialStockId',
- label: '搴撳瓨璁板綍',
- component: markRaw(WmMaterialStockSelect),
+ fieldName: 'issueLineId',
+ label: '棰嗘枡璁板綍',
+ component: markRaw(WmProductIssueLineSelect),
componentProps: {
- // 閫夋嫨搴撳瓨璁板綍鍚庯紝鑷姩鍥炲~鐗╂枡/鎵规/鏁伴噺
- onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => {
+ workOrderId,
+ onChange: async (line?: MesWmProductIssueLineApi.ProductIssueLine) => {
await formApi?.setValues({
- batchCode: stock?.batchCode,
- batchId: stock?.batchId,
- itemId: stock?.itemId,
- materialDisplayName: stock
- ? [stock.itemName, stock.specification].filter(Boolean).join(' | ')
+ batchCode: line?.batchCode,
+ batchId: line?.batchId,
+ itemId: line?.itemId,
+ materialDisplayName: line
+ ? [line.itemName, line.specification].filter(Boolean).join(' | ')
: undefined,
- quantity: stock?.quantity,
- quantityMax: stock?.quantity,
+ quantity: line?.quantity,
+ quantityMax: line?.quantity,
});
},
- virtualFilter: 'only',
},
rules: 'selectRequired',
},
@@ -390,7 +394,7 @@
component: 'Input',
componentProps: {
disabled: true,
- placeholder: '閫夋嫨搴撳瓨鍚庤嚜鍔ㄥ甫鍑�',
+ placeholder: '閫夋嫨棰嗘枡璁板綍鍚庤嚜鍔ㄥ甫鍑�',
},
},
{
@@ -399,7 +403,7 @@
component: 'Input',
componentProps: {
disabled: true,
- placeholder: '閫夋嫨搴撳瓨鍚庤嚜鍔ㄥ甫鍑�',
+ placeholder: '閫夋嫨棰嗘枡璁板綍鍚庤嚜鍔ㄥ甫鍑�',
},
},
{
diff --git a/src/views/wls/returnissue/modules/form.vue b/src/views/wls/returnissue/modules/form.vue
index 1546dd4..2d340e9 100644
--- a/src/views/wls/returnissue/modules/form.vue
+++ b/src/views/wls/returnissue/modules/form.vue
@@ -198,7 +198,7 @@
<template v-if="formData?.id">
<Divider>鐗╂枡淇℃伅</Divider>
<div class="mx-4">
- <LineList :form-type="formType" :issue-id="formData.id" />
+ <LineList :form-type="formType" :issue-id="formData.id" :work-order-id="formData.workOrderId" />
</div>
</template>
<template #prepend-footer>
diff --git a/src/views/wls/returnissue/modules/line-form.vue b/src/views/wls/returnissue/modules/line-form.vue
index fc72468..4e14a8d 100644
--- a/src/views/wls/returnissue/modules/line-form.vue
+++ b/src/views/wls/returnissue/modules/line-form.vue
@@ -19,7 +19,8 @@
const emit = defineEmits(['success']);
const formData = ref<MesWmReturnIssueLineApi.ReturnIssueLine>();
-const issueId = ref<number>(); // 鎵�灞為��鏂欏崟缂栧彿
+const issueId = ref<number>();
+const workOrderId = ref<number>();
const getTitle = computed(() => {
return formData.value?.id
@@ -69,17 +70,16 @@
formData.value = undefined;
return;
}
- formApi.setState({ schema: useLineFormSchema(formApi) });
- // 鍔犺浇鏁版嵁
- const data = modalApi.getData<{ id?: number; issueId: number }>();
+ const data = modalApi.getData<{ id?: number; issueId: number; workOrderId?: number }>();
issueId.value = data.issueId;
+ workOrderId.value = data.workOrderId;
+ formApi.setState({ schema: useLineFormSchema(formApi, workOrderId.value) });
if (!data.id) {
return;
}
modalApi.lock();
try {
formData.value = await getReturnIssueLine(data.id);
- // 璁剧疆鍒� values锛屽苟鏋勫缓鐗╂枡灞曠ず鍚�
await formApi.setValues({
...formData.value,
materialDisplayName: [formData.value.itemName, formData.value.specification]
diff --git a/src/views/wls/returnissue/modules/line-list.vue b/src/views/wls/returnissue/modules/line-list.vue
index 98c6682..14c7ccf 100644
--- a/src/views/wls/returnissue/modules/line-list.vue
+++ b/src/views/wls/returnissue/modules/line-list.vue
@@ -29,6 +29,7 @@
const props = defineProps<{
formType: FormType;
issueId: number;
+ workOrderId?: number;
}>();
const isEditable = computed(() =>
@@ -61,12 +62,12 @@
/** 娣诲姞鐗╂枡 */
function handleCreate() {
- lineFormModalApi.setData({ issueId: props.issueId }).open();
+ lineFormModalApi.setData({ issueId: props.issueId, workOrderId: props.workOrderId }).open();
}
/** 缂栬緫鐗╂枡 */
function handleEdit(row: MesWmReturnIssueLineApi.ReturnIssueLine) {
- lineFormModalApi.setData({ id: row.id, issueId: props.issueId }).open();
+ lineFormModalApi.setData({ id: row.id, issueId: props.issueId, workOrderId: props.workOrderId }).open();
}
/** 鍒犻櫎鐗╂枡 */
--
Gitblit v1.9.3