From 64c2870483568cdeb0206661249a19c5b06de8fe Mon Sep 17 00:00:00 2001
From: zhuguifei <312353457@qq.com>
Date: 星期三, 04 三月 2026 12:52:52 +0800
Subject: [PATCH] feat(moudule(qa)): 新增喂丝机对应关系、第三方储丝柜信息视图等管理界面
---
ruoyi-plus-soybean/src/router/elegant/routes.ts | 38
ruoyi-plus-soybean/src/views/analy/store-silk/index.vue | 273 +++++++
ruoyi-plus-soybean/src/typings/api/md.shift.api.d.ts | 77 +
ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-search.vue | 101 ++
ruoyi-plus-soybean/src/views/md/shift/index.vue | 254 ++++++
ruoyi-plus-soybean/src/service/api/analy/feed-match.ts | 35
ruoyi-plus-soybean/src/views/md/shift/modules/shift-operate-drawer.vue | 175 ++++
ruoyi-plus-soybean/src/views/md/shift/modules/shift-search.vue | 77 +
ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-search.vue | 79 ++
ruoyi-plus-soybean/src/typings/api/analy.feed-match.api.d.ts | 118 +++
ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-operate-drawer.vue | 281 +++++++
ruoyi-plus-soybean/src/router/elegant/imports.ts | 3
ruoyi-plus-soybean/src/typings/elegant-router.d.ts | 8
ruoyi-plus-soybean/src/typings/components.d.ts | 4
ruoyi-plus-soybean/src/views/analy/feed-match/index.vue | 337 ++++++++
ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-operate-drawer.vue | 176 ++++
RuoYi-Vue-Plus/开发日志.md | 113 --
ruoyi-plus-soybean/src/service/api/md/shift.ts | 35
ruoyi-plus-soybean/src/typings/api/analy.store-silk.api.d.ts | 74 +
ruoyi-plus-soybean/src/service/api/analy/store-silk.ts | 35
ruoyi-plus-soybean/src/router/elegant/transform.ts | 4
21 files changed, 2,189 insertions(+), 108 deletions(-)
diff --git "a/RuoYi-Vue-Plus/\345\274\200\345\217\221\346\227\245\345\277\227.md" "b/RuoYi-Vue-Plus/\345\274\200\345\217\221\346\227\245\345\277\227.md"
index 3e10167..002cc10 100644
--- "a/RuoYi-Vue-Plus/\345\274\200\345\217\221\346\227\245\345\277\227.md"
+++ "b/RuoYi-Vue-Plus/\345\274\200\345\217\221\346\227\245\345\277\227.md"
@@ -8,112 +8,9 @@
- 1.鏂板鎴愬搧妫� 妫�楠屾壒娆� 绠$悊椤甸潰
- 2.鏁版嵁搴撹〃锛� qm_batch
```
--- 鍒涘缓妫�楠屾壒娆¤〃
-CREATE TABLE QM_BATCH (
- ID VARCHAR(50) NOT NULL,
- BATCH_CODE VARCHAR(50),
- BATCH_NAME VARCHAR(50),
- TYP VARCHAR(20),
- EQP_CODE VARCHAR(50),
- MAT_CODE VARCHAR(50),
- JUDGE_CODE VARCHAR(50),
- BATCH_DATE DATE,
- ISFLAG VARCHAR(2),
- ENABLED VARCHAR(2),
- TOTAL_NUM NUMERIC(22),
- RESULTS VARCHAR(50),
- APPROVER VARCHAR(50),
- AUDITOR VARCHAR(50),
- CREATER VARCHAR(50),
- TAB_DATE DATE,
- VER_NAME VARCHAR(50),
- VER_CODE VARCHAR(50),
- ARCH_DATE VARCHAR(50),
- FLAG VARCHAR(20),
- TO_MES_DATE DATE,
- FROM_MES_DATE DATE,
- DELETED NUMERIC(22),
- BATCH_DES VARCHAR(200),
- CATEGORY VARCHAR(2),
- MAKENO VARCHAR(60),
- SHIFTEQPNO VARCHAR(32),
- BOXNO VARCHAR(60),
- PID VARCHAR(50),
- REVIEWER VARCHAR(50),
- RVCOUNT NUMERIC(22),
- STATE VARCHAR(2),
- REVIEW_TIME DATE,
- AUDIT_TIME DATE,
- SPEC VARCHAR(50),
- APPROVE_TIME DATE,
- UNIT VARCHAR(50),
- ARRIVAL_TIME DATE,
- STORAGE_PLACE VARCHAR(50),
- CHECKER VARCHAR(20),
- RECEIVE_TIME DATE,
- INSP_TIME DATE,
- STORER VARCHAR(50),
- ISVERIFY VARCHAR(10),
- ISCHK VARCHAR(10),
- BAK1 VARCHAR(100),
- BAK2 VARCHAR(100),
- CONSTRAINT PK_QM_BATCH PRIMARY KEY (ID)
-);
-
--- 娣诲姞娉ㄩ噴锛堝彲閫夛級
-COMMENT ON TABLE QM_BATCH IS '妫�楠屾壒娆¤〃';
-
-COMMENT ON COLUMN QM_BATCH.ID IS '缂栫爜';
-COMMENT ON COLUMN QM_BATCH.BATCH_CODE IS '鎵规浠g爜';
-COMMENT ON COLUMN QM_BATCH.BATCH_NAME IS '鎵规鍚嶇О';
-COMMENT ON COLUMN QM_BATCH.TYP IS 'A-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�';
-COMMENT ON COLUMN QM_BATCH.EQP_CODE IS '鏈哄彴浠g爜';
-COMMENT ON COLUMN QM_BATCH.MAT_CODE IS '鐗屽彿';
-COMMENT ON COLUMN QM_BATCH.JUDGE_CODE IS '鍒ゅ畾渚濇嵁浠g爜';
-COMMENT ON COLUMN QM_BATCH.BATCH_DATE IS '鎵规鐢熸垚鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.ISFLAG IS '浣跨敤鏍囧織';
-COMMENT ON COLUMN QM_BATCH.ENABLED IS '鍚敤鏍囧織';
-COMMENT ON COLUMN QM_BATCH.TOTAL_NUM IS '鍒拌揣鎬婚噺';
-COMMENT ON COLUMN QM_BATCH.RESULTS IS '缁煎悎鍒ゅ畾';
-COMMENT ON COLUMN QM_BATCH.APPROVER IS '鎵瑰噯浜�';
-COMMENT ON COLUMN QM_BATCH.AUDITOR IS '瀹℃牳浜�';
-COMMENT ON COLUMN QM_BATCH.CREATER IS '鍒涘缓浜�';
-COMMENT ON COLUMN QM_BATCH.TAB_DATE IS '鍒惰〃鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.VER_NAME IS '鐗堟湰鍚嶇О';
-COMMENT ON COLUMN QM_BATCH.VER_CODE IS '鐗堟湰缂栧彿';
-COMMENT ON COLUMN QM_BATCH.ARCH_DATE IS '淇濆瓨鏈�';
-COMMENT ON COLUMN QM_BATCH.FLAG IS '0-鏈笂浼爉es,1-宸蹭笂浼�, 3-浠嶮ES涓嬭浇';
-COMMENT ON COLUMN QM_BATCH.TO_MES_DATE IS '涓婁紶MES鏃堕棿';
-COMMENT ON COLUMN QM_BATCH.FROM_MES_DATE IS '浠嶮ES鏃堕棿涓嬭浇';
-COMMENT ON COLUMN QM_BATCH.DELETED IS '鍒犻櫎鏍囧織';
-COMMENT ON COLUMN QM_BATCH.BATCH_DES IS '鎵规鎻忚堪';
-COMMENT ON COLUMN QM_BATCH.CATEGORY IS '绫诲埆 0锛氭垚鍝� 1锛氳緟鏉�';
-COMMENT ON COLUMN QM_BATCH.MAKENO IS '鍗峰埗宸ュ彿';
-COMMENT ON COLUMN QM_BATCH.SHIFTEQPNO IS '鐝鏈哄彿';
-COMMENT ON COLUMN QM_BATCH.BOXNO IS '瑁呯鍙�';
-COMMENT ON COLUMN QM_BATCH.PID IS '鐖舵壒娆″彿';
-COMMENT ON COLUMN QM_BATCH.REVIEWER IS '澶嶆牳浜�';
-COMMENT ON COLUMN QM_BATCH.RVCOUNT IS '澶嶆娆℃暟';
-COMMENT ON COLUMN QM_BATCH.STATE IS '鎵规鐘舵��';
-COMMENT ON COLUMN QM_BATCH.REVIEW_TIME IS '澶嶆牳鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.AUDIT_TIME IS '瀹℃牳鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.SPEC IS '瑙勬牸';
-COMMENT ON COLUMN QM_BATCH.APPROVE_TIME IS '鎵瑰噯鏃堕棿';
-COMMENT ON COLUMN QM_BATCH.UNIT IS '鍒拌揣鍗曚綅';
-COMMENT ON COLUMN QM_BATCH.ARRIVAL_TIME IS '鍒拌揣鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.STORAGE_PLACE IS '瀛樻斁鍦扮偣';
-COMMENT ON COLUMN QM_BATCH.CHECKER IS '妫�楠屽憳';
-COMMENT ON COLUMN QM_BATCH.RECEIVE_TIME IS '鎺ュ崟鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.INSP_TIME IS '鎶ユ鏃ユ湡';
-COMMENT ON COLUMN QM_BATCH.STORER IS '浠撳簱淇濈鍛�';
-COMMENT ON COLUMN QM_BATCH.ISVERIFY IS '鏄惁楠岃瘉';
-COMMENT ON COLUMN QM_BATCH.ISCHK IS '鏄惁妫�楠�';
-COMMENT ON COLUMN QM_BATCH.BAK1 IS '澶囩敤1';
-COMMENT ON COLUMN QM_BATCH.BAK2 IS '澶囩敤2';
-
--- 鍒涘缓绱㈠紩锛堟牴鎹父鐢ㄦ煡璇㈡潯浠跺垱寤猴級
-CREATE INDEX IDX_QM_BATCH_BATCH_CODE ON QM_BATCH(BATCH_CODE);
-CREATE INDEX IDX_QM_BATCH_BATCH_DATE ON QM_BATCH(BATCH_DATE);
-CREATE INDEX IDX_QM_BATCH_TYP ON QM_BATCH(TYP);
-CREATE INDEX IDX_QM_BATCH_MAT_CODE ON QM_BATCH(MAT_CODE);
```
+
+#### 20260302
+- 寰呭姙浜嬮」
+- [ ] 鐩墠鍌ㄤ笣鏌滀俊鎭俊鎭病鏈変粠瑙嗗浘涓幏鍙栵紝浣跨敤oracle_store_silk琛ㄦā鎷�
+
diff --git a/ruoyi-plus-soybean/src/router/elegant/imports.ts b/ruoyi-plus-soybean/src/router/elegant/imports.ts
index c533376..4751a41 100755
--- a/ruoyi-plus-soybean/src/router/elegant/imports.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/imports.ts
@@ -23,13 +23,16 @@
"social-callback": () => import("@/views/_builtin/social-callback/index.vue"),
"user-center": () => import("@/views/_builtin/user-center/index.vue"),
about: () => import("@/views/about/index.vue"),
+ "analy_feed-match": () => import("@/views/analy/feed-match/index.vue"),
analy_hoister: () => import("@/views/analy/hoister/index.vue"),
"analy_output-analy": () => import("@/views/analy/output-analy/index.vue"),
analy_packer: () => import("@/views/analy/packer/index.vue"),
analy_roller: () => import("@/views/analy/roller/index.vue"),
+ "analy_store-silk": () => import("@/views/analy/store-silk/index.vue"),
demo_demo: () => import("@/views/demo/demo/index.vue"),
demo_tree: () => import("@/views/demo/tree/index.vue"),
home: () => import("@/views/home/index.vue"),
+ md_shift: () => import("@/views/md/shift/index.vue"),
monitor_cache: () => import("@/views/monitor/cache/index.vue"),
monitor_logininfor: () => import("@/views/monitor/logininfor/index.vue"),
monitor_online: () => import("@/views/monitor/online/index.vue"),
diff --git a/ruoyi-plus-soybean/src/router/elegant/routes.ts b/ruoyi-plus-soybean/src/router/elegant/routes.ts
index 6a6900a..274f98a 100755
--- a/ruoyi-plus-soybean/src/router/elegant/routes.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/routes.ts
@@ -60,6 +60,15 @@
},
children: [
{
+ name: 'analy_feed-match',
+ path: '/analy/feed-match',
+ component: 'view.analy_feed-match',
+ meta: {
+ title: 'analy_feed-match',
+ i18nKey: 'route.analy_feed-match'
+ }
+ },
+ {
name: 'analy_hoister',
path: '/analy/hoister',
component: 'view.analy_hoister',
@@ -93,6 +102,15 @@
meta: {
title: 'analy_roller',
i18nKey: 'route.analy_roller'
+ }
+ },
+ {
+ name: 'analy_store-silk',
+ path: '/analy/store-silk',
+ component: 'view.analy_store-silk',
+ meta: {
+ title: 'analy_store-silk',
+ i18nKey: 'route.analy_store-silk'
}
}
]
@@ -163,6 +181,26 @@
}
},
{
+ name: 'md',
+ path: '/md',
+ component: 'layout.base',
+ meta: {
+ title: 'md',
+ i18nKey: 'route.md'
+ },
+ children: [
+ {
+ name: 'md_shift',
+ path: '/md/shift',
+ component: 'view.md_shift',
+ meta: {
+ title: 'md_shift',
+ i18nKey: 'route.md_shift'
+ }
+ }
+ ]
+ },
+ {
name: 'monitor',
path: '/monitor',
component: 'layout.base',
diff --git a/ruoyi-plus-soybean/src/router/elegant/transform.ts b/ruoyi-plus-soybean/src/router/elegant/transform.ts
index 8a15977..7459606 100755
--- a/ruoyi-plus-soybean/src/router/elegant/transform.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/transform.ts
@@ -172,16 +172,20 @@
"500": "/500",
"about": "/about",
"analy": "/analy",
+ "analy_feed-match": "/analy/feed-match",
"analy_hoister": "/analy/hoister",
"analy_output-analy": "/analy/output-analy",
"analy_packer": "/analy/packer",
"analy_roller": "/analy/roller",
+ "analy_store-silk": "/analy/store-silk",
"demo": "/demo",
"demo_demo": "/demo/demo",
"demo_tree": "/demo/tree",
"home": "/home",
"iframe-page": "/iframe-page/:url",
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
+ "md": "/md",
+ "md_shift": "/md/shift",
"monitor": "/monitor",
"monitor_cache": "/monitor/cache",
"monitor_logininfor": "/monitor/logininfor",
diff --git a/ruoyi-plus-soybean/src/service/api/analy/feed-match.ts b/ruoyi-plus-soybean/src/service/api/analy/feed-match.ts
new file mode 100644
index 0000000..5fa81eb
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/analy/feed-match.ts
@@ -0,0 +1,35 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇鍠備笣鏈哄搴斿叧绯诲垪琛� */
+export function fetchGetFeedMatchList (params?: Api.Analy.FeedMatchSearchParams) {
+ return request<Api.Analy.FeedMatchList>({
+ url: '/analy/feedMatch/list',
+ method: 'get',
+ params
+ });
+}
+/** 鏂板鍠備笣鏈哄搴斿叧绯� */
+export function fetchCreateFeedMatch (data: Api.Analy.FeedMatchOperateParams) {
+ return request<boolean>({
+ url: '/analy/feedMatch',
+ method: 'post',
+ data
+ });
+}
+
+/** 淇敼鍠備笣鏈哄搴斿叧绯� */
+export function fetchUpdateFeedMatch (data: Api.Analy.FeedMatchOperateParams) {
+ return request<boolean>({
+ url: '/analy/feedMatch',
+ method: 'put',
+ data
+ });
+}
+
+/** 鎵归噺鍒犻櫎鍠備笣鏈哄搴斿叧绯� */
+export function fetchBatchDeleteFeedMatch (times: CommonType.IdType[]) {
+ return request<boolean>({
+ url: `/analy/feedMatch/${times.join(',')}`,
+ method: 'delete'
+ });
+}
diff --git a/ruoyi-plus-soybean/src/service/api/analy/store-silk.ts b/ruoyi-plus-soybean/src/service/api/analy/store-silk.ts
new file mode 100644
index 0000000..17a3a12
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/analy/store-silk.ts
@@ -0,0 +1,35 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇鍌ㄤ笣鏌滀骇閲忓垪琛� */
+export function fetchGetStoreSilkList (params?: Api.Analy.StoreSilkSearchParams) {
+ return request<Api.Analy.StoreSilkList>({
+ url: '/analy/storeSilk/list',
+ method: 'get',
+ params
+ });
+}
+/** 鏂板鍌ㄤ笣鏌滀骇閲� */
+export function fetchCreateStoreSilk (data: Api.Analy.StoreSilkOperateParams) {
+ return request<boolean>({
+ url: '/analy/storeSilk',
+ method: 'post',
+ data
+ });
+}
+
+/** 淇敼鍌ㄤ笣鏌滀骇閲� */
+export function fetchUpdateStoreSilk (data: Api.Analy.StoreSilkOperateParams) {
+ return request<boolean>({
+ url: '/analy/storeSilk',
+ method: 'put',
+ data
+ });
+}
+
+/** 鎵归噺鍒犻櫎鍌ㄤ笣鏌滀骇閲� */
+export function fetchBatchDeleteStoreSilk (ids: CommonType.IdType[]) {
+ return request<boolean>({
+ url: `/analy/storeSilk/${ids.join(',')}`,
+ method: 'delete'
+ });
+}
diff --git a/ruoyi-plus-soybean/src/service/api/md/shift.ts b/ruoyi-plus-soybean/src/service/api/md/shift.ts
new file mode 100644
index 0000000..11d2d1e
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/md/shift.ts
@@ -0,0 +1,35 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇鐝鍒楄〃 */
+export function fetchGetShiftList (params?: Api.Md.ShiftSearchParams) {
+ return request<Api.Md.ShiftList>({
+ url: '/md/shift/list',
+ method: 'get',
+ params
+ });
+}
+/** 鏂板鐝 */
+export function fetchCreateShift (data: Api.Md.ShiftOperateParams) {
+ return request<boolean>({
+ url: '/md/shift',
+ method: 'post',
+ data
+ });
+}
+
+/** 淇敼鐝 */
+export function fetchUpdateShift (data: Api.Md.ShiftOperateParams) {
+ return request<boolean>({
+ url: '/md/shift',
+ method: 'put',
+ data
+ });
+}
+
+/** 鎵归噺鍒犻櫎鐝 */
+export function fetchBatchDeleteShift (ids: CommonType.IdType[]) {
+ return request<boolean>({
+ url: `/md/shift/${ids.join(',')}`,
+ method: 'delete'
+ });
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/analy.feed-match.api.d.ts b/ruoyi-plus-soybean/src/typings/api/analy.feed-match.api.d.ts
new file mode 100644
index 0000000..36a8609
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/analy.feed-match.api.d.ts
@@ -0,0 +1,118 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+ /**
+ * namespace Analy
+ *
+ * backend api module: "Analy"
+ */
+ namespace Analy {
+ /** feed match */
+ type FeedMatch = Common.CommonRecord<{
+ /** 鏃堕棿鎴� */
+ time: string;
+ /** 鐝+鏈哄彴 */
+ key: string;
+ /** 鏁版嵁鏇存柊鏃堕棿 */
+ dacUpTime: string;
+ /** 1#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖 */
+ fs11: string;
+ /** 1#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖 */
+ fs12: string;
+ /** 2#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖 */
+ fs21: string;
+ /** 2#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖 */
+ fs22: string;
+ /** 3#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖 */
+ fs31: string;
+ /** 3#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖 */
+ fs32: string;
+ /** 4#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖 */
+ fs41: string;
+ /** 4#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖 */
+ fs42: string;
+ /** 1#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe01: number;
+ /** 2#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe02: number;
+ /** 3#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe03: number;
+ /** 4#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe04: number;
+ /** 5#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe05: number;
+ /** 6#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe06: number;
+ /** 7#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe07: number;
+ /** 8#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe08: number;
+ /** 9#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe09: number;
+ /** 10#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe10: number;
+ /** 11#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe11: number;
+ /** 12#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬� */
+ pipe12: number;
+ /** 鍠備笣鏈虹姸鎬� 1-杩炴帴 0-鏂紑 */
+ wsjState: number;
+ /** 鐝 */
+ shift: number;
+ /** 鏈哄彴 */
+ equNo: number;
+ /** 澶囨敞 */
+ remark: string;
+ }>;
+
+ /** feed match search params */
+ type FeedMatchSearchParams = CommonType.RecordNullable<
+ Pick<
+ Api.Analy.FeedMatch,
+ | 'time'
+ | 'key'
+ > &
+ Api.Common.CommonSearchParams
+ >;
+
+ /** feed match operate params */
+ type FeedMatchOperateParams = CommonType.RecordNullable<
+ Pick<
+ Api.Analy.FeedMatch,
+ | 'time'
+ | 'key'
+ | 'dacUpTime'
+ | 'fs11'
+ | 'fs12'
+ | 'fs21'
+ | 'fs22'
+ | 'fs31'
+ | 'fs32'
+ | 'fs41'
+ | 'fs42'
+ | 'pipe01'
+ | 'pipe02'
+ | 'pipe03'
+ | 'pipe04'
+ | 'pipe05'
+ | 'pipe06'
+ | 'pipe07'
+ | 'pipe08'
+ | 'pipe09'
+ | 'pipe10'
+ | 'pipe11'
+ | 'pipe12'
+ | 'wsjState'
+ | 'shift'
+ | 'equNo'
+ | 'remark'
+ >
+ >;
+
+ /** feed match list */
+ type FeedMatchList = Api.Common.PaginatingQueryRecord<FeedMatch>;
+ }
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/analy.store-silk.api.d.ts b/ruoyi-plus-soybean/src/typings/api/analy.store-silk.api.d.ts
new file mode 100644
index 0000000..3b11f30
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/analy.store-silk.api.d.ts
@@ -0,0 +1,74 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+ /**
+ * namespace Analy
+ *
+ * backend api module: "Analy"
+ */
+ namespace Analy {
+ /** store silk */
+ type StoreSilk = Common.CommonRecord<{
+ /** id */
+ id: CommonType.IdType;
+ /** 鐗屽彿 */
+ materialname: string;
+ /** 鎵规鍙� */
+ batchcode: string;
+ /** 鎶曟枡鏃ユ湡 */
+ actualstarttime: string;
+ /** 鎶曟枡閲嶉噺 */
+ jobinput: number;
+ /** 鎹熻�楅噸閲� */
+ weightloss: number;
+ /** 鍑哄彾涓濈巼 */
+ slkrate: number;
+ /** 鍌ㄤ笣鏌滈噸閲� */
+ weight: number;
+ /** 鍌ㄤ笣鏌滃嚭鏂欏紑濮嬫椂闂� */
+ distimebegin: string;
+ /** 鍌ㄤ笣鏌滃嚭鏂欑粨鏉熸椂闂� */
+ distimeend: string;
+ /** 鏌滃瓙鍙�(鏈綅) */
+ siloid: CommonType.IdType;
+ }>;
+
+ /** store silk search params */
+ type StoreSilkSearchParams = CommonType.RecordNullable<
+ Pick<
+ Api.Analy.StoreSilk,
+ | 'materialname'
+ | 'batchcode'
+ | 'actualstarttime'
+ | 'distimebegin'
+ | 'distimeend'
+ | 'siloid'
+ > &
+ Api.Common.CommonSearchParams
+ >;
+
+ /** store silk operate params */
+ type StoreSilkOperateParams = CommonType.RecordNullable<
+ Pick<
+ Api.Analy.StoreSilk,
+ | 'id'
+ | 'materialname'
+ | 'batchcode'
+ | 'actualstarttime'
+ | 'jobinput'
+ | 'weightloss'
+ | 'slkrate'
+ | 'weight'
+ | 'distimebegin'
+ | 'distimeend'
+ | 'siloid'
+ >
+ >;
+
+ /** store silk list */
+ type StoreSilkList = Api.Common.PaginatingQueryRecord<StoreSilk>;
+ }
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/md.shift.api.d.ts b/ruoyi-plus-soybean/src/typings/api/md.shift.api.d.ts
new file mode 100644
index 0000000..9d44c00
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/md.shift.api.d.ts
@@ -0,0 +1,77 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+ /**
+ * namespace Md
+ *
+ * backend api module: "Md"
+ */
+ namespace Md {
+ /** shift */
+ type Shift = Common.CommonRecord<{
+ /** ud */
+ id: CommonType.IdType;
+ /** 杞﹂棿澶栭敭 */
+ wsId: CommonType.IdType;
+ /** 缂栫爜 */
+ code: string;
+ /** 鍚嶇О */
+ name: string;
+ /** 鐝寮�濮嬫椂闂� */
+ stim: string;
+ /** 鐝缁撴潫鏃堕棿 */
+ etim: string;
+ /** 鎺掑簭 */
+ seq: number;
+ /** 鍚敤 */
+ enable: number;
+ /** 鍒犻櫎 */
+ del: number;
+ /** 鍒涘缓鐢ㄦ埛 */
+ createUserName: string;
+ /** 鍒涘缓鏃堕棿 */
+ createUserTime: string;
+ /** 鏇存柊鐢ㄦ埛 */
+ updateUserName: string;
+ /** 鏇存柊鏃堕棿 */
+ updateUserTime: string;
+ }>;
+
+ /** shift search params */
+ type ShiftSearchParams = CommonType.RecordNullable<
+ Pick<
+ Api.Md.Shift,
+ | 'code'
+ | 'name'
+ | 'enable'
+ > &
+ Api.Common.CommonSearchParams
+ >;
+
+ /** shift operate params */
+ type ShiftOperateParams = CommonType.RecordNullable<
+ Pick<
+ Api.Md.Shift,
+ | 'id'
+ | 'wsId'
+ | 'code'
+ | 'name'
+ | 'stim'
+ | 'etim'
+ | 'seq'
+ | 'enable'
+ | 'del'
+ | 'createUserName'
+ | 'createUserTime'
+ | 'updateUserName'
+ | 'updateUserTime'
+ >
+ >;
+
+ /** shift list */
+ type ShiftList = Api.Common.PaginatingQueryRecord<Shift>;
+ }
+}
diff --git a/ruoyi-plus-soybean/src/typings/components.d.ts b/ruoyi-plus-soybean/src/typings/components.d.ts
index a3a54e0..24c0b46 100755
--- a/ruoyi-plus-soybean/src/typings/components.d.ts
+++ b/ruoyi-plus-soybean/src/typings/components.d.ts
@@ -58,6 +58,7 @@
IconMdiGithub: typeof import('~icons/mdi/github')['default']
IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
+ IconMdiTableLarge: typeof import('~icons/mdi/table-large')['default']
IconQuillCollapse: typeof import('~icons/quill/collapse')['default']
IconQuillExpand: typeof import('~icons/quill/expand')['default']
IconSimpleIconsGitee: typeof import('~icons/simple-icons/gitee')['default']
@@ -76,6 +77,7 @@
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
NButton: typeof import('naive-ui')['NButton']
+ NButtonGroup: typeof import('naive-ui')['NButtonGroup']
NCard: typeof import('naive-ui')['NCard']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NCode: typeof import('naive-ui')['NCode']
@@ -209,6 +211,7 @@
const IconMdiGithub: typeof import('~icons/mdi/github')['default']
const IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
const IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
+ const IconMdiTableLarge: typeof import('~icons/mdi/table-large')['default']
const IconQuillCollapse: typeof import('~icons/quill/collapse')['default']
const IconQuillExpand: typeof import('~icons/quill/expand')['default']
const IconSimpleIconsGitee: typeof import('~icons/simple-icons/gitee')['default']
@@ -227,6 +230,7 @@
const NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
const NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
const NButton: typeof import('naive-ui')['NButton']
+ const NButtonGroup: typeof import('naive-ui')['NButtonGroup']
const NCard: typeof import('naive-ui')['NCard']
const NCheckbox: typeof import('naive-ui')['NCheckbox']
const NCode: typeof import('naive-ui')['NCode']
diff --git a/ruoyi-plus-soybean/src/typings/elegant-router.d.ts b/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
index 91d02d6..cd2f9bb 100755
--- a/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
+++ b/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
@@ -26,16 +26,20 @@
"500": "/500";
"about": "/about";
"analy": "/analy";
+ "analy_feed-match": "/analy/feed-match";
"analy_hoister": "/analy/hoister";
"analy_output-analy": "/analy/output-analy";
"analy_packer": "/analy/packer";
"analy_roller": "/analy/roller";
+ "analy_store-silk": "/analy/store-silk";
"demo": "/demo";
"demo_demo": "/demo/demo";
"demo_tree": "/demo/tree";
"home": "/home";
"iframe-page": "/iframe-page/:url";
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
+ "md": "/md";
+ "md_shift": "/md/shift";
"monitor": "/monitor";
"monitor_cache": "/monitor/cache";
"monitor_logininfor": "/monitor/logininfor";
@@ -105,6 +109,7 @@
| "home"
| "iframe-page"
| "login"
+ | "md"
| "monitor"
| "qm"
| "social-callback"
@@ -136,13 +141,16 @@
| "social-callback"
| "user-center"
| "about"
+ | "analy_feed-match"
| "analy_hoister"
| "analy_output-analy"
| "analy_packer"
| "analy_roller"
+ | "analy_store-silk"
| "demo_demo"
| "demo_tree"
| "home"
+ | "md_shift"
| "monitor_cache"
| "monitor_logininfor"
| "monitor_online"
diff --git a/ruoyi-plus-soybean/src/views/analy/feed-match/index.vue b/ruoyi-plus-soybean/src/views/analy/feed-match/index.vue
new file mode 100644
index 0000000..f76c41a
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/analy/feed-match/index.vue
@@ -0,0 +1,337 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteFeedMatch, fetchGetFeedMatchList } from '@/service/api/analy/feed-match';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import FeedMatchOperateDrawer from './modules/feed-match-operate-drawer.vue';
+import FeedMatchSearch from './modules/feed-match-search.vue';
+
+defineOptions({
+ name: 'FeedMatchList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const searchParams = ref<Api.Analy.FeedMatchSearchParams>({
+ pageNum: 1,
+ pageSize: 10,
+ time: null,
+ key: null,
+ params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+ useNaivePaginatedTable({
+ api: () => fetchGetFeedMatchList(searchParams.value),
+ transform: response => defaultTransform(response),
+ onPaginationParamsChange: params => {
+ searchParams.value.pageNum = params.page;
+ searchParams.value.pageSize = params.pageSize;
+ },
+ columns: () => [
+ {
+ type: 'selection',
+ align: 'center',
+ width: 48
+ },
+ {
+ key: 'index',
+ title: $t('common.index'),
+ align: 'center',
+ width: 64,
+ render: (_, index) => index + 1
+ },
+ {
+ key: 'time',
+ title: '鏃堕棿鎴�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'key',
+ title: '鐝+鏈哄彴',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'dacUpTime',
+ title: '鏁版嵁鏇存柊鏃堕棿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs11',
+ title: '1#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs12',
+ title: '1#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs21',
+ title: '2#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs22',
+ title: '2#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs31',
+ title: '3#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs32',
+ title: '3#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs41',
+ title: '4#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fs42',
+ title: '4#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe01',
+ title: '1#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe02',
+ title: '2#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe03',
+ title: '3#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe04',
+ title: '4#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe05',
+ title: '5#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe06',
+ title: '6#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe07',
+ title: '7#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe08',
+ title: '8#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe09',
+ title: '9#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe10',
+ title: '10#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe11',
+ title: '11#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pipe12',
+ title: '12#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'wsjState',
+ title: '鍠備笣鏈虹姸鎬� 1-杩炴帴 0-鏂紑',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'shift',
+ title: '鐝',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'equNo',
+ title: '鏈哄彴',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'remark',
+ title: '澶囨敞',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'operate',
+ title: $t('common.operate'),
+ align: 'center',
+ width: 130,
+ render: row => {
+ const divider = () => {
+ if (!hasAuth('analy:feedMatch:edit') || !hasAuth('analy:feedMatch:remove')) {
+ return null;
+ }
+ return <NDivider vertical />;
+ };
+
+ const editBtn = () => {
+ if (!hasAuth('analy:feedMatch:edit')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="primary"
+ icon="material-symbols:drive-file-rename-outline-outline"
+ tooltipContent={$t('common.edit')}
+ onClick={() => edit(row.time)}
+ />
+ );
+ };
+
+ const deleteBtn = () => {
+ if (!hasAuth('analy:feedMatch:remove')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="error"
+ icon="material-symbols:delete-outline"
+ tooltipContent={$t('common.delete')}
+ popconfirmContent={$t('common.confirmDelete')}
+ onPositiveClick={() => handleDelete(row.time)}
+ />
+ );
+ };
+
+ return (
+ <div class="flex-center gap-8px">
+ {editBtn()}
+ {divider()}
+ {deleteBtn()}
+ </div>
+ );
+ }
+ }
+ ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+ useTableOperate(data, 'time', getData);
+
+async function handleBatchDelete() {
+ // request
+ const { error } = await fetchBatchDeleteFeedMatch(checkedRowKeys.value);
+ if (error) return;
+ onBatchDeleted();
+}
+
+async function handleDelete(time: CommonType.IdType) {
+ // request
+ const { error } = await fetchBatchDeleteFeedMatch([time]);
+ if (error) return;
+ onDeleted();
+}
+
+function edit(time: CommonType.IdType) {
+ handleEdit(time);
+}
+
+function handleExport() {
+ download('/analy/feedMatch/export', searchParams.value, `鍠備笣鏈哄搴斿叧绯籣${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+ <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+ <FeedMatchSearch v-model:model="searchParams" @search="getDataByPage" />
+ <NCard title="鍠備笣鏈哄搴斿叧绯诲垪琛�" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+ <template #header-extra>
+ <TableHeaderOperation
+ v-model:columns="columnChecks"
+ :disabled-delete="checkedRowKeys.length === 0"
+ :loading="loading"
+ :show-add="hasAuth('analy:feedMatch:add')"
+ :show-delete="hasAuth('analy:feedMatch:remove')"
+ :show-export="hasAuth('analy:feedMatch:export')"
+ @add="handleAdd"
+ @delete="handleBatchDelete"
+ @export="handleExport"
+ @refresh="getData"
+ />
+ </template>
+ <NDataTable
+ v-model:checked-row-keys="checkedRowKeys"
+ :columns="columns"
+ :data="data"
+ size="small"
+ :flex-height="!appStore.isMobile"
+ :scroll-x="scrollX"
+ :loading="loading"
+ remote
+ :row-key="row => row.time"
+ :pagination="mobilePagination"
+ class="sm:h-full"
+ />
+ <FeedMatchOperateDrawer
+ v-model:visible="drawerVisible"
+ :operate-type="operateType"
+ :row-data="editingData"
+ @submitted="getDataByPage"
+ />
+ </NCard>
+ </div>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-operate-drawer.vue b/ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-operate-drawer.vue
new file mode 100644
index 0000000..77b0221
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-operate-drawer.vue
@@ -0,0 +1,281 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateFeedMatch, fetchUpdateFeedMatch } from '@/service/api/analy/feed-match';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'FeedMatchOperateDrawer'
+});
+
+interface Props {
+ /** the type of operation */
+ operateType: NaiveUI.TableOperateType;
+ /** the edit row data */
+ rowData?: Api.Analy.FeedMatch | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+ (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+ default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+
+const title = computed(() => {
+ const titles: Record<NaiveUI.TableOperateType, string> = {
+ add: '鏂板鍠備笣鏈哄搴斿叧绯�',
+ edit: '缂栬緫鍠備笣鏈哄搴斿叧绯�'
+ };
+ return titles[props.operateType];
+});
+
+type Model = Api.Analy.FeedMatchOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+ return {
+ time: null,
+ key: '',
+ dacUpTime: '',
+ fs11: '',
+ fs12: '',
+ fs21: '',
+ fs22: '',
+ fs31: '',
+ fs32: '',
+ fs41: '',
+ fs42: '',
+ pipe01: null,
+ pipe02: null,
+ pipe03: null,
+ pipe04: null,
+ pipe05: null,
+ pipe06: null,
+ pipe07: null,
+ pipe08: null,
+ pipe09: null,
+ pipe10: null,
+ pipe11: null,
+ pipe12: null,
+ wsjState: null,
+ shift: null,
+ equNo: null,
+ remark: ''
+ };
+}
+
+type RuleKey = Extract<
+ keyof Model,
+ | 'time'
+ | 'key'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+ time: createRequiredRule('鏃堕棿鎴充笉鑳戒负绌�'),
+ key: createRequiredRule('鐝+鏈哄彴涓嶈兘涓虹┖'),
+};
+
+function handleUpdateModelWhenEdit() {
+ model.value = createDefaultModel();
+
+ if (props.operateType === 'edit' && props.rowData) {
+ Object.assign(model.value, jsonClone(props.rowData));
+ }
+}
+
+function closeDrawer() {
+ visible.value = false;
+}
+
+async function handleSubmit() {
+ await validate();
+
+ const { time, key, dacUpTime, fs11, fs12, fs21, fs22, fs31, fs32, fs41, fs42, pipe01, pipe02, pipe03, pipe04, pipe05, pipe06, pipe07, pipe08, pipe09, pipe10, pipe11, pipe12, wsjState, shift, equNo, remark } = model.value;
+
+ // request
+ if (props.operateType === 'add') {
+ const { error } = await fetchCreateFeedMatch({ time, key, dacUpTime, fs11, fs12, fs21, fs22, fs31, fs32, fs41, fs42, pipe01, pipe02, pipe03, pipe04, pipe05, pipe06, pipe07, pipe08, pipe09, pipe10, pipe11, pipe12, wsjState, shift, equNo, remark });
+ if (error) return;
+ }
+
+ if (props.operateType === 'edit') {
+ const { error } = await fetchUpdateFeedMatch({ time, key, dacUpTime, fs11, fs12, fs21, fs22, fs31, fs32, fs41, fs42, pipe01, pipe02, pipe03, pipe04, pipe05, pipe06, pipe07, pipe08, pipe09, pipe10, pipe11, pipe12, wsjState, shift, equNo, remark });
+ if (error) return;
+ }
+
+ window.$message?.success($t('common.updateSuccess'));
+ closeDrawer();
+ emit('submitted');
+}
+
+watch(visible, () => {
+ if (visible.value) {
+ handleUpdateModelWhenEdit();
+ restoreValidation();
+ }
+});
+</script>
+
+<template>
+ <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+ <NDrawerContent :title="title" :native-scrollbar="false" closable>
+ <NForm ref="formRef" :model="model" :rules="rules">
+ <NFormItem label="鏃堕棿鎴�" path="time">
+ <NDatePicker
+ v-model:formatted-value="model.time"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鐝+鏈哄彴" path="key">
+ <NInput
+ v-model:value="model.key"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏ョ彮娆�+鏈哄彴"
+ />
+ </NFormItem>
+ <NFormItem label="鏁版嵁鏇存柊鏃堕棿" path="dacUpTime">
+ <NInput
+ v-model:value="model.dacUpTime"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏ユ暟鎹洿鏂版椂闂�"
+ />
+ </NFormItem>
+ <NFormItem label="1#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖" path="fs11">
+ <NInput
+ v-model:value="model.fs11"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�1#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="1#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖" path="fs12">
+ <NInput
+ v-model:value="model.fs12"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�1#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="2#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖" path="fs21">
+ <NInput
+ v-model:value="model.fs21"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�2#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="2#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖" path="fs22">
+ <NInput
+ v-model:value="model.fs22"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�2#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="3#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖" path="fs31">
+ <NInput
+ v-model:value="model.fs31"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�3#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="3#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖" path="fs32">
+ <NInput
+ v-model:value="model.fs32"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�3#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="4#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖" path="fs41">
+ <NInput
+ v-model:value="model.fs41"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�4#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="4#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖" path="fs42">
+ <NInput
+ v-model:value="model.fs42"
+ :rows="3"
+ type="textarea"
+ placeholder="璇疯緭鍏�4#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖"
+ />
+ </NFormItem>
+ <NFormItem label="1#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe01">
+ <NInput v-model:value="model.pipe01" placeholder="璇疯緭鍏�1#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="2#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe02">
+ <NInput v-model:value="model.pipe02" placeholder="璇疯緭鍏�2#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="3#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe03">
+ <NInput v-model:value="model.pipe03" placeholder="璇疯緭鍏�3#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="4#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe04">
+ <NInput v-model:value="model.pipe04" placeholder="璇疯緭鍏�4#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="5#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe05">
+ <NInput v-model:value="model.pipe05" placeholder="璇疯緭鍏�5#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="6#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe06">
+ <NInput v-model:value="model.pipe06" placeholder="璇疯緭鍏�6#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="7#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe07">
+ <NInput v-model:value="model.pipe07" placeholder="璇疯緭鍏�7#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="8#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe08">
+ <NInput v-model:value="model.pipe08" placeholder="璇疯緭鍏�8#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="9#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe09">
+ <NInput v-model:value="model.pipe09" placeholder="璇疯緭鍏�9#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="10#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe10">
+ <NInput v-model:value="model.pipe10" placeholder="璇疯緭鍏�10#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="11#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe11">
+ <NInput v-model:value="model.pipe11" placeholder="璇疯緭鍏�11#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="12#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" path="pipe12">
+ <NInput v-model:value="model.pipe12" placeholder="璇疯緭鍏�12#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�" />
+ </NFormItem>
+ <NFormItem label="鍠備笣鏈虹姸鎬� 1-杩炴帴 0-鏂紑" path="wsjState">
+ <NInput v-model:value="model.wsjState" placeholder="璇疯緭鍏ュ杺涓濇満鐘舵�� 1-杩炴帴 0-鏂紑" />
+ </NFormItem>
+ <NFormItem label="鐝" path="shift">
+ <NInput v-model:value="model.shift" placeholder="璇疯緭鍏ョ彮娆�" />
+ </NFormItem>
+ <NFormItem label="鏈哄彴" path="equNo">
+ <NInput v-model:value="model.equNo" placeholder="璇疯緭鍏ユ満鍙�" />
+ </NFormItem>
+ <NFormItem label="澶囨敞" path="remark">
+ <NInput v-model:value="model.remark" placeholder="璇疯緭鍏ュ娉�" />
+ </NFormItem>
+ </NForm>
+ <template #footer>
+ <NSpace :size="16">
+ <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+ <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+ </NSpace>
+ </template>
+ </NDrawerContent>
+ </NDrawer>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-search.vue b/ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-search.vue
new file mode 100644
index 0000000..4482f5d
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/analy/feed-match/modules/feed-match-search.vue
@@ -0,0 +1,79 @@
+<script setup lang="ts">
+import { toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'FeedMatchSearch'
+});
+
+interface Emits {
+ (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Analy.FeedMatchSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+function resetModel() {
+ Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+ await restoreValidation();
+ resetModel();
+ emit('search');
+}
+
+async function search() {
+ await validate();
+ emit('search');
+}
+</script>
+
+<template>
+ <NCard :bordered="false" size="small" class="card-wrapper">
+ <NCollapse>
+ <NCollapseItem :title="$t('common.search')" name="analy-feed-match-search">
+ <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+ <NGrid responsive="screen" item-responsive>
+ <NFormItemGi span="24 s:12 m:6" label="鏃堕棿鎴�" label-width="auto" path="time" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="model.time"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鐝+鏈哄彴" label-width="auto" path="key" class="pr-24px">
+ <NInput v-model:value="model.key" placeholder="璇疯緭鍏ョ彮娆�+鏈哄彴" />
+ </NFormItemGi>
+ <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+ <NSpace class="w-full" justify="end">
+ <NButton @click="reset">
+ <template #icon>
+ <icon-ic-round-refresh class="text-icon" />
+ </template>
+ {{ $t('common.reset') }}
+ </NButton>
+ <NButton type="primary" ghost @click="search">
+ <template #icon>
+ <icon-ic-round-search class="text-icon" />
+ </template>
+ {{ $t('common.search') }}
+ </NButton>
+ </NSpace>
+ </NFormItemGi>
+ </NGrid>
+ </NForm>
+ </NCollapseItem>
+ </NCollapse>
+ </NCard>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue b/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue
new file mode 100644
index 0000000..addf095
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/analy/store-silk/index.vue
@@ -0,0 +1,273 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteStoreSilk, fetchGetStoreSilkList } from '@/service/api/analy/store-silk';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import StoreSilkOperateDrawer from './modules/store-silk-operate-drawer.vue';
+import StoreSilkSearch from './modules/store-silk-search.vue';
+
+defineOptions({
+ name: 'StoreSilkList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const searchParams = ref<Api.Analy.StoreSilkSearchParams>({
+ pageNum: 1,
+ pageSize: 10,
+ materialname: null,
+ batchcode: null,
+ actualstarttime: null,
+ distimebegin: null,
+ distimeend: null,
+ siloid: null,
+ params: {}
+});
+
+const tableSize = ref<'tiny' | 'small' | 'medium' | 'large'>('small');
+
+function handleTableSizeChange(size: 'tiny' | 'small' | 'medium' | 'large') {
+ tableSize.value = size;
+}
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+ useNaivePaginatedTable({
+ api: () => fetchGetStoreSilkList(searchParams.value),
+ transform: response => defaultTransform(response),
+ onPaginationParamsChange: params => {
+ searchParams.value.pageNum = params.page;
+ searchParams.value.pageSize = params.pageSize;
+ },
+ columns: () => [
+ {
+ type: 'selection',
+ align: 'center',
+ width: 48
+ },
+ {
+ key: 'index',
+ title: $t('common.index'),
+ align: 'center',
+ width: 64,
+ render: (_, index) => index + 1
+ },
+ {
+ key: 'materialname',
+ title: '鐗屽彿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'batchcode',
+ title: '鎵规鍙�',
+ align: 'center',
+ minWidth: 130
+ },
+ {
+ key: 'roller',
+ title: '鍗锋帴浜ч噺',
+ align: 'center',
+ minWidth: 100
+ },
+ {
+ key: 'packer',
+ title: '鍖呰浜ч噺',
+ align: 'center',
+ minWidth: 100
+ },
+ {
+ key: 'actualstarttime',
+ title: '鎶曟枡鏃ユ湡',
+ align: 'center',
+ width: 180
+ },
+ {
+ key: 'jobinput',
+ title: '鎶曟枡閲嶉噺',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'weight',
+ title: '鍌ㄤ笣鏌滈噸閲�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'distimebegin',
+ title: '鍌ㄤ笣鏌滃嚭鏂欏紑濮嬫椂闂�',
+ align: 'center',
+ width: 180
+ },
+ {
+ key: 'distimeend',
+ title: '鍌ㄤ笣鏌滃嚭鏂欑粨鏉熸椂闂�',
+ align: 'center',
+ width: 180
+ },
+ {
+ key: 'siloid',
+ title: '鏌滃瓙鍙�(鏈綅)',
+ align: 'center',
+ width: 160
+ },
+ {
+ key: 'operate',
+ title: $t('common.operate'),
+ align: 'center',
+ fixed: 'right',
+ width: 130,
+ render: row => {
+ const divider = () => {
+ if (!hasAuth('analy:storeSilk:edit') || !hasAuth('analy:storeSilk:remove')) {
+ return null;
+ }
+ return <NDivider vertical />;
+ };
+
+ const editBtn = () => {
+ if (!hasAuth('analy:storeSilk:edit')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="primary"
+ icon="material-symbols:drive-file-rename-outline-outline"
+ tooltipContent={$t('common.edit')}
+ onClick={() => edit(row.id)}
+ />
+ );
+ };
+
+ const deleteBtn = () => {
+ if (!hasAuth('analy:storeSilk:remove')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="error"
+ icon="material-symbols:delete-outline"
+ tooltipContent={$t('common.delete')}
+ popconfirmContent={$t('common.confirmDelete')}
+ onPositiveClick={() => handleDelete(row.id)}
+ />
+ );
+ };
+
+ return (
+ <div class="flex-center gap-8px">
+ {editBtn()}
+ {divider()}
+ {deleteBtn()}
+ </div>
+ );
+ }
+ }
+ ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+ useTableOperate(data, 'id', getData);
+
+async function handleBatchDelete() {
+ // request
+ const { error } = await fetchBatchDeleteStoreSilk(checkedRowKeys.value);
+ if (error) return;
+ onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+ // request
+ const { error } = await fetchBatchDeleteStoreSilk([id]);
+ if (error) return;
+ onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+ handleEdit(id);
+}
+
+function handleExport() {
+ download('/analy/storeSilk/export', searchParams.value, `鍌ㄤ笣鏌滀骇閲廮${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+ <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+ <StoreSilkSearch v-model:model="searchParams" @search="getDataByPage" />
+ <NCard title="鍌ㄤ笣鏌滀骇閲忓垪琛�" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+ <template #header-extra>
+ <TableHeaderOperation
+ v-model:columns="columnChecks"
+ :disabled-delete="checkedRowKeys.length === 0"
+ :loading="loading"
+ :show-add="hasAuth('analy:storeSilk:add')"
+ :show-delete="hasAuth('analy:storeSilk:remove')"
+ :show-export="hasAuth('analy:storeSilk:export')"
+ @add="handleAdd"
+ @delete="handleBatchDelete"
+ @export="handleExport"
+ @refresh="getData"
+ >
+ <template #suffix>
+ <NPopover placement="bottom-end" trigger="click">
+ <template #trigger>
+ <NButton size="small">
+ <template #icon>
+ <icon-mdi-table-large class="text-icon" />
+ </template>
+ 琛ㄦ牸澶у皬
+ </NButton>
+ </template>
+ <NRadioGroup :value="tableSize" @update:value="handleTableSizeChange">
+ <NSpace vertical>
+ <NRadio value="tiny">mini</NRadio>
+ <NRadio value="small">灏�</NRadio>
+ <NRadio value="medium">涓�</NRadio>
+ <NRadio value="large">澶�</NRadio>
+ </NSpace>
+ </NRadioGroup>
+ </NPopover>
+ </template>
+ </TableHeaderOperation>
+ </template>
+ <NDataTable
+ v-model:checked-row-keys="checkedRowKeys"
+ :columns="columns"
+ :data="data"
+ :size="tableSize"
+ :flex-height="!appStore.isMobile"
+ :scroll-x="scrollX"
+ :loading="loading"
+ remote
+ :row-key="row => row.id"
+ :pagination="mobilePagination"
+ :class="['sm:h-full', tableSize === 'tiny' ? 'table-size-mini' : '']"
+ />
+ <StoreSilkOperateDrawer
+ v-model:visible="drawerVisible"
+ :operate-type="operateType"
+ :row-data="editingData"
+ @submitted="getDataByPage"
+ />
+ </NCard>
+ </div>
+</template>
+
+<style scoped>
+:deep(.table-size-mini .n-data-table-th),
+:deep(.table-size-mini .n-data-table-td) {
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+</style>
diff --git a/ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-operate-drawer.vue b/ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-operate-drawer.vue
new file mode 100644
index 0000000..523341c
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-operate-drawer.vue
@@ -0,0 +1,176 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateStoreSilk, fetchUpdateStoreSilk } from '@/service/api/analy/store-silk';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'StoreSilkOperateDrawer'
+});
+
+interface Props {
+ /** the type of operation */
+ operateType: NaiveUI.TableOperateType;
+ /** the edit row data */
+ rowData?: Api.Analy.StoreSilk | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+ (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+ default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+
+const title = computed(() => {
+ const titles: Record<NaiveUI.TableOperateType, string> = {
+ add: '鏂板鍌ㄤ笣鏌滀骇閲�',
+ edit: '缂栬緫鍌ㄤ笣鏌滀骇閲�'
+ };
+ return titles[props.operateType];
+});
+
+type Model = Api.Analy.StoreSilkOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+ return {
+ id: null,
+ materialname: '',
+ batchcode: '',
+ actualstarttime: null,
+ jobinput: null,
+ weightloss: null,
+ slkrate: null,
+ weight: null,
+ distimebegin: null,
+ distimeend: null,
+ siloid: ''
+ };
+}
+
+type RuleKey = Extract<
+ keyof Model,
+ | 'id'
+ | 'materialname'
+ | 'batchcode'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+ id: createRequiredRule('id涓嶈兘涓虹┖'),
+ materialname: createRequiredRule('鐗屽彿涓嶈兘涓虹┖'),
+ batchcode: createRequiredRule('鎵规鍙蜂笉鑳戒负绌�'),
+};
+
+function handleUpdateModelWhenEdit() {
+ model.value = createDefaultModel();
+
+ if (props.operateType === 'edit' && props.rowData) {
+ Object.assign(model.value, jsonClone(props.rowData));
+ }
+}
+
+function closeDrawer() {
+ visible.value = false;
+}
+
+async function handleSubmit() {
+ await validate();
+
+ const { id, materialname, batchcode, actualstarttime, jobinput, weightloss, slkrate, weight, distimebegin, distimeend, siloid } = model.value;
+
+ // request
+ if (props.operateType === 'add') {
+ const { error } = await fetchCreateStoreSilk({ materialname, batchcode, actualstarttime, jobinput, weightloss, slkrate, weight, distimebegin, distimeend, siloid });
+ if (error) return;
+ }
+
+ if (props.operateType === 'edit') {
+ const { error } = await fetchUpdateStoreSilk({ id, materialname, batchcode, actualstarttime, jobinput, weightloss, slkrate, weight, distimebegin, distimeend, siloid });
+ if (error) return;
+ }
+
+ window.$message?.success($t('common.updateSuccess'));
+ closeDrawer();
+ emit('submitted');
+}
+
+watch(visible, () => {
+ if (visible.value) {
+ handleUpdateModelWhenEdit();
+ restoreValidation();
+ }
+});
+</script>
+
+<template>
+ <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+ <NDrawerContent :title="title" :native-scrollbar="false" closable>
+ <NForm ref="formRef" :model="model" :rules="rules">
+ <NFormItem label="鐗屽彿" path="materialname">
+ <NInput v-model:value="model.materialname" placeholder="璇疯緭鍏ョ墝鍙�" />
+ </NFormItem>
+ <NFormItem label="鎵规鍙�" path="batchcode">
+ <NInput v-model:value="model.batchcode" placeholder="璇疯緭鍏ユ壒娆″彿" />
+ </NFormItem>
+ <NFormItem label="鎶曟枡鏃ユ湡" path="actualstarttime">
+ <NDatePicker
+ v-model:formatted-value="model.actualstarttime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鎶曟枡閲嶉噺" path="jobinput">
+ <NInput v-model:value="model.jobinput" placeholder="璇疯緭鍏ユ姇鏂欓噸閲�" />
+ </NFormItem>
+ <NFormItem label="鎹熻�楅噸閲�" path="weightloss">
+ <NInput v-model:value="model.weightloss" placeholder="璇疯緭鍏ユ崯鑰楅噸閲�" />
+ </NFormItem>
+ <NFormItem label="鍑哄彾涓濈巼" path="slkrate">
+ <NInput v-model:value="model.slkrate" placeholder="璇疯緭鍏ュ嚭鍙朵笣鐜�" />
+ </NFormItem>
+ <NFormItem label="鍌ㄤ笣鏌滈噸閲�" path="weight">
+ <NInput v-model:value="model.weight" placeholder="璇疯緭鍏ュ偍涓濇煖閲嶉噺" />
+ </NFormItem>
+ <NFormItem label="鍌ㄤ笣鏌滃嚭鏂欏紑濮嬫椂闂�" path="distimebegin">
+ <NDatePicker
+ v-model:formatted-value="model.distimebegin"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鍌ㄤ笣鏌滃嚭鏂欑粨鏉熸椂闂�" path="distimeend">
+ <NDatePicker
+ v-model:formatted-value="model.distimeend"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鏌滃瓙鍙�(鏈綅)" path="siloid">
+ <NInput v-model:value="model.siloid" placeholder="璇疯緭鍏ユ煖瀛愬彿(鏈綅)" />
+ </NFormItem>
+ </NForm>
+ <template #footer>
+ <NSpace :size="16">
+ <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+ <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+ </NSpace>
+ </template>
+ </NDrawerContent>
+ </NDrawer>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-search.vue b/ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-search.vue
new file mode 100644
index 0000000..2c64d93
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-search.vue
@@ -0,0 +1,101 @@
+<script setup lang="ts">
+import { toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'StoreSilkSearch'
+});
+
+interface Emits {
+ (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Analy.StoreSilkSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+function resetModel() {
+ Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+ await restoreValidation();
+ resetModel();
+ emit('search');
+}
+
+async function search() {
+ await validate();
+ emit('search');
+}
+</script>
+
+<template>
+ <NCard :bordered="false" size="small" class="card-wrapper">
+ <NCollapse>
+ <NCollapseItem :title="$t('common.search')" name="analy-store-silk-search">
+ <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+ <NGrid responsive="screen" item-responsive>
+ <NFormItemGi span="24 s:12 m:6" label="鐗屽彿" label-width="auto" path="materialname" class="pr-24px">
+ <NInput v-model:value="model.materialname" placeholder="璇疯緭鍏ョ墝鍙�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鎵规鍙�" label-width="auto" path="batchcode" class="pr-24px">
+ <NInput v-model:value="model.batchcode" placeholder="璇疯緭鍏ユ壒娆″彿" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鎶曟枡鏃ユ湡" label-width="auto" path="actualstarttime" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="model.actualstarttime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鍌ㄤ笣鏌滃嚭鏂欏紑濮嬫椂闂�" label-width="auto" path="distimebegin" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="model.distimebegin"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鍌ㄤ笣鏌滃嚭鏂欑粨鏉熸椂闂�" label-width="auto" path="distimeend" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="model.distimeend"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鏌滃瓙鍙�(鏈綅)" label-width="auto" path="siloid" class="pr-24px">
+ <NInput v-model:value="model.siloid" placeholder="璇疯緭鍏ユ煖瀛愬彿(鏈綅)" />
+ </NFormItemGi>
+ <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+ <NSpace class="w-full" justify="end">
+ <NButton @click="reset">
+ <template #icon>
+ <icon-ic-round-refresh class="text-icon" />
+ </template>
+ {{ $t('common.reset') }}
+ </NButton>
+ <NButton type="primary" ghost @click="search">
+ <template #icon>
+ <icon-ic-round-search class="text-icon" />
+ </template>
+ {{ $t('common.search') }}
+ </NButton>
+ </NSpace>
+ </NFormItemGi>
+ </NGrid>
+ </NForm>
+ </NCollapseItem>
+ </NCollapse>
+ </NCard>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/shift/index.vue b/ruoyi-plus-soybean/src/views/md/shift/index.vue
new file mode 100644
index 0000000..d28d6b0
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/shift/index.vue
@@ -0,0 +1,254 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteShift, fetchGetShiftList } from '@/service/api/md/shift';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import ShiftOperateDrawer from './modules/shift-operate-drawer.vue';
+import ShiftSearch from './modules/shift-search.vue';
+
+defineOptions({
+ name: 'ShiftList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const searchParams = ref<Api.Md.ShiftSearchParams>({
+ pageNum: 1,
+ pageSize: 10,
+ code: null,
+ name: null,
+ enable: null,
+ params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+ useNaivePaginatedTable({
+ api: () => fetchGetShiftList(searchParams.value),
+ transform: response => defaultTransform(response),
+ onPaginationParamsChange: params => {
+ searchParams.value.pageNum = params.page;
+ searchParams.value.pageSize = params.pageSize;
+ },
+ columns: () => [
+ {
+ type: 'selection',
+ align: 'center',
+ width: 48
+ },
+ {
+ key: 'index',
+ title: $t('common.index'),
+ align: 'center',
+ width: 64,
+ render: (_, index) => index + 1
+ },
+ {
+ key: 'id',
+ title: 'ud',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'wsId',
+ title: '杞﹂棿澶栭敭',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'code',
+ title: '缂栫爜',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'name',
+ title: '鍚嶇О',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'stim',
+ title: '鐝寮�濮嬫椂闂�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'etim',
+ title: '鐝缁撴潫鏃堕棿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'seq',
+ title: '鎺掑簭',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'enable',
+ title: '鍚敤',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'del',
+ title: '鍒犻櫎',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'createUserName',
+ title: '鍒涘缓鐢ㄦ埛',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'createUserTime',
+ title: '鍒涘缓鏃堕棿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'updateUserName',
+ title: '鏇存柊鐢ㄦ埛',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'updateUserTime',
+ title: '鏇存柊鏃堕棿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'operate',
+ title: $t('common.operate'),
+ align: 'center',
+ width: 130,
+ render: row => {
+ const divider = () => {
+ if (!hasAuth('md:shift:edit') || !hasAuth('md:shift:remove')) {
+ return null;
+ }
+ return <NDivider vertical />;
+ };
+
+ const editBtn = () => {
+ if (!hasAuth('md:shift:edit')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="primary"
+ icon="material-symbols:drive-file-rename-outline-outline"
+ tooltipContent={$t('common.edit')}
+ onClick={() => edit(row.id)}
+ />
+ );
+ };
+
+ const deleteBtn = () => {
+ if (!hasAuth('md:shift:remove')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="error"
+ icon="material-symbols:delete-outline"
+ tooltipContent={$t('common.delete')}
+ popconfirmContent={$t('common.confirmDelete')}
+ onPositiveClick={() => handleDelete(row.id)}
+ />
+ );
+ };
+
+ return (
+ <div class="flex-center gap-8px">
+ {editBtn()}
+ {divider()}
+ {deleteBtn()}
+ </div>
+ );
+ }
+ }
+ ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+ useTableOperate(data, 'id', getData);
+
+async function handleBatchDelete() {
+ // request
+ const { error } = await fetchBatchDeleteShift(checkedRowKeys.value);
+ if (error) return;
+ onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+ // request
+ const { error } = await fetchBatchDeleteShift([id]);
+ if (error) return;
+ onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+ handleEdit(id);
+}
+
+function handleExport() {
+ download('/md/shift/export', searchParams.value, `鐝_${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+ <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+ <ShiftSearch v-model:model="searchParams" @search="getDataByPage" />
+ <NCard title="鐝鍒楄〃" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+ <template #header-extra>
+ <TableHeaderOperation
+ v-model:columns="columnChecks"
+ :disabled-delete="checkedRowKeys.length === 0"
+ :loading="loading"
+ :show-add="hasAuth('md:shift:add')"
+ :show-delete="hasAuth('md:shift:remove')"
+ :show-export="hasAuth('md:shift:export')"
+ @add="handleAdd"
+ @delete="handleBatchDelete"
+ @export="handleExport"
+ @refresh="getData"
+ />
+ </template>
+ <NDataTable
+ v-model:checked-row-keys="checkedRowKeys"
+ :columns="columns"
+ :data="data"
+ size="small"
+ :flex-height="!appStore.isMobile"
+ :scroll-x="scrollX"
+ :loading="loading"
+ remote
+ :row-key="row => row.id"
+ :pagination="mobilePagination"
+ class="sm:h-full"
+ />
+ <ShiftOperateDrawer
+ v-model:visible="drawerVisible"
+ :operate-type="operateType"
+ :row-data="editingData"
+ @submitted="getDataByPage"
+ />
+ </NCard>
+ </div>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/shift/modules/shift-operate-drawer.vue b/ruoyi-plus-soybean/src/views/md/shift/modules/shift-operate-drawer.vue
new file mode 100644
index 0000000..e98ba6e
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/shift/modules/shift-operate-drawer.vue
@@ -0,0 +1,175 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateShift, fetchUpdateShift } from '@/service/api/md/shift';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'ShiftOperateDrawer'
+});
+
+interface Props {
+ /** the type of operation */
+ operateType: NaiveUI.TableOperateType;
+ /** the edit row data */
+ rowData?: Api.Md.Shift | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+ (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+ default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+
+const title = computed(() => {
+ const titles: Record<NaiveUI.TableOperateType, string> = {
+ add: '鏂板鐝',
+ edit: '缂栬緫鐝'
+ };
+ return titles[props.operateType];
+});
+
+type Model = Api.Md.ShiftOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+ return {
+ id: '',
+ wsId: '',
+ code: '',
+ name: '',
+ stim: '',
+ etim: '',
+ seq: null,
+ enable: null,
+ del: null,
+ createUserName: '',
+ createUserTime: null,
+ updateUserName: '',
+ updateUserTime: null
+ };
+}
+
+type RuleKey = Extract<
+ keyof Model,
+ | 'id'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+ id: createRequiredRule('ud涓嶈兘涓虹┖'),
+};
+
+function handleUpdateModelWhenEdit() {
+ model.value = createDefaultModel();
+
+ if (props.operateType === 'edit' && props.rowData) {
+ Object.assign(model.value, jsonClone(props.rowData));
+ }
+}
+
+function closeDrawer() {
+ visible.value = false;
+}
+
+async function handleSubmit() {
+ await validate();
+
+ const { id, wsId, code, name, stim, etim, seq, enable, del, createUserName, createUserTime, updateUserName, updateUserTime } = model.value;
+
+ // request
+ if (props.operateType === 'add') {
+ const { error } = await fetchCreateShift({ wsId, code, name, stim, etim, seq, enable, del, createUserName, createUserTime, updateUserName, updateUserTime });
+ if (error) return;
+ }
+
+ if (props.operateType === 'edit') {
+ const { error } = await fetchUpdateShift({ id, wsId, code, name, stim, etim, seq, enable, del, createUserName, createUserTime, updateUserName, updateUserTime });
+ if (error) return;
+ }
+
+ window.$message?.success($t('common.updateSuccess'));
+ closeDrawer();
+ emit('submitted');
+}
+
+watch(visible, () => {
+ if (visible.value) {
+ handleUpdateModelWhenEdit();
+ restoreValidation();
+ }
+});
+</script>
+
+<template>
+ <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+ <NDrawerContent :title="title" :native-scrollbar="false" closable>
+ <NForm ref="formRef" :model="model" :rules="rules">
+ <NFormItem label="杞﹂棿澶栭敭" path="wsId">
+ <NInput v-model:value="model.wsId" placeholder="璇疯緭鍏ヨ溅闂村閿�" />
+ </NFormItem>
+ <NFormItem label="缂栫爜" path="code">
+ <NInput v-model:value="model.code" placeholder="璇疯緭鍏ョ紪鐮�" />
+ </NFormItem>
+ <NFormItem label="鍚嶇О" path="name">
+ <NInput v-model:value="model.name" placeholder="璇疯緭鍏ュ悕绉�" />
+ </NFormItem>
+ <NFormItem label="鐝寮�濮嬫椂闂�" path="stim">
+ <NInput v-model:value="model.stim" placeholder="璇疯緭鍏ョ彮娆″紑濮嬫椂闂�" />
+ </NFormItem>
+ <NFormItem label="鐝缁撴潫鏃堕棿" path="etim">
+ <NInput v-model:value="model.etim" placeholder="璇疯緭鍏ョ彮娆$粨鏉熸椂闂�" />
+ </NFormItem>
+ <NFormItem label="鎺掑簭" path="seq">
+ <NInput v-model:value="model.seq" placeholder="璇疯緭鍏ユ帓搴�" />
+ </NFormItem>
+ <NFormItem label="鍚敤" path="enable">
+ <NInput v-model:value="model.enable" placeholder="璇疯緭鍏ュ惎鐢�" />
+ </NFormItem>
+ <NFormItem label="鍒犻櫎" path="del">
+ <NInput v-model:value="model.del" placeholder="璇疯緭鍏ュ垹闄�" />
+ </NFormItem>
+ <NFormItem label="鍒涘缓鐢ㄦ埛" path="createUserName">
+ <NInput v-model:value="model.createUserName" placeholder="璇疯緭鍏ュ垱寤虹敤鎴�" />
+ </NFormItem>
+ <NFormItem label="鍒涘缓鏃堕棿" path="createUserTime">
+ <NDatePicker
+ v-model:formatted-value="model.createUserTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鏇存柊鐢ㄦ埛" path="updateUserName">
+ <NInput v-model:value="model.updateUserName" placeholder="璇疯緭鍏ユ洿鏂扮敤鎴�" />
+ </NFormItem>
+ <NFormItem label="鏇存柊鏃堕棿" path="updateUserTime">
+ <NDatePicker
+ v-model:formatted-value="model.updateUserTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ </NForm>
+ <template #footer>
+ <NSpace :size="16">
+ <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+ <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+ </NSpace>
+ </template>
+ </NDrawerContent>
+ </NDrawer>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/shift/modules/shift-search.vue b/ruoyi-plus-soybean/src/views/md/shift/modules/shift-search.vue
new file mode 100644
index 0000000..d544a66
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/shift/modules/shift-search.vue
@@ -0,0 +1,77 @@
+<script setup lang="ts">
+import { toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'ShiftSearch'
+});
+
+interface Emits {
+ (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Md.ShiftSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+function resetModel() {
+ Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+ await restoreValidation();
+ resetModel();
+ emit('search');
+}
+
+async function search() {
+ await validate();
+ emit('search');
+}
+</script>
+
+<template>
+ <NCard :bordered="false" size="small" class="card-wrapper">
+ <NCollapse>
+ <NCollapseItem :title="$t('common.search')" name="md-shift-search">
+ <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+ <NGrid responsive="screen" item-responsive>
+ <NFormItemGi span="24 s:12 m:6" label="缂栫爜" label-width="auto" path="code" class="pr-24px">
+ <NInput v-model:value="model.code" placeholder="璇疯緭鍏ョ紪鐮�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鍚嶇О" label-width="auto" path="name" class="pr-24px">
+ <NInput v-model:value="model.name" placeholder="璇疯緭鍏ュ悕绉�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="鍚敤" label-width="auto" path="enable" class="pr-24px">
+ <NInput v-model:value="model.enable" placeholder="璇疯緭鍏ュ惎鐢�" />
+ </NFormItemGi>
+ <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+ <NSpace class="w-full" justify="end">
+ <NButton @click="reset">
+ <template #icon>
+ <icon-ic-round-refresh class="text-icon" />
+ </template>
+ {{ $t('common.reset') }}
+ </NButton>
+ <NButton type="primary" ghost @click="search">
+ <template #icon>
+ <icon-ic-round-search class="text-icon" />
+ </template>
+ {{ $t('common.search') }}
+ </NButton>
+ </NSpace>
+ </NFormItemGi>
+ </NGrid>
+ </NForm>
+ </NCollapseItem>
+ </NCollapse>
+ </NCard>
+</template>
+
+<style scoped></style>
--
Gitblit v1.9.3