p-pc-ui 1.3.12 → 1.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -62,7 +62,7 @@ const confirmClick = async () => {
62
62
 
63
63
  <template>
64
64
  <a-modal
65
- v-model:visible="show"
65
+ v-model:open="show"
66
66
  :width="width"
67
67
  centered
68
68
  wrapClassName="p-modal"
@@ -44,7 +44,7 @@ const confirmClick = async () => {
44
44
  </script>
45
45
 
46
46
  <template>
47
- <a-modal v-model:visible="show" :width="width" centered wrapClassName="p-modal">
47
+ <a-modal v-model:open="show" :width="width" centered wrapClassName="p-modal">
48
48
  <template #title v-if="title">
49
49
  <div class="modal-title">
50
50
  {{ title }}
@@ -60,7 +60,6 @@ const confirmClick = async () => {
60
60
  <a-button
61
61
  class="modal-btn modal-cancel-btn"
62
62
  @click="show = false"
63
- @keydown.enter.prevent="show = false"
64
63
  >
65
64
  取消
66
65
  </a-button>
@@ -72,7 +71,6 @@ const confirmClick = async () => {
72
71
  backgroundColor: confrimBtnBgColor,
73
72
  }"
74
73
  @click="confirmClick"
75
- @keydown.enter.prevent="confirmClick"
76
74
  :loading="loading"
77
75
  >
78
76
  确定
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <Modal v-model:visible="visible" :title="title" :width="modalWidth" okText="确定" cancel-text="取消" @ok="ok" centered
2
+ <Modal v-model:open="visible" :title="title" :width="modalWidth" okText="确定" cancel-text="取消" @ok="ok" centered
3
3
  @cancel="cancel">
4
4
  <div style="max-height: 600px; overflow-y: auto; padding-right: 80px;margin-top: 30px;">
5
5
  <p-form v-if="formRenderData.length > 0" ref="PFormRef" :render-data="formRenderData"
@@ -51,22 +51,26 @@ onMounted(() => {
51
51
  initFormValue = {};
52
52
  }
53
53
 
54
+ const renderDataMap = new Map(_.cloneDeep(renderFormData).map((val) => [val.key, val]));
54
55
  const filterRenderData: any = [];
55
56
  for (const renderKey of renderKeys || renderFormData.map((val) => val.key)) {
56
- const renderItem = _.cloneDeep(renderFormData).find((val) => val.key == renderKey);
57
+ const renderItem = renderDataMap.get(renderKey);
57
58
  if (!_.isEmpty(renderItem)) {
58
59
  filterRenderData.push(renderItem);
59
60
  }
60
61
  }
61
62
 
62
63
  formRenderData.value = filterRenderData;
63
- console.log(formRenderData)
64
64
  })
65
65
 
66
66
 
67
67
  const ok = async () => {
68
- let formData = await PFormRef.value.getFormData();
69
- emits('confirm', formData)
68
+ try {
69
+ let formData = await PFormRef.value.getFormData();
70
+ emits('confirm', formData)
71
+ } catch (error) {
72
+ console.warn('Form validation failed:', error);
73
+ }
70
74
  }
71
75
 
72
76
 
@@ -77,4 +81,4 @@ const cancel = () => {
77
81
 
78
82
  </script>
79
83
 
80
- <style scoped></style>
84
+ <style scoped></style>
@@ -2,7 +2,7 @@
2
2
  // import "viewerjs/dist/viewer.css";
3
3
  import { api as viewerApi } from "v-viewer";
4
4
  import PForm from "../p-form/p-form.vue";
5
- import { h, ref, reactive, onMounted, toRaw, computed } from "vue";
5
+ import { ref, reactive, onMounted, toRaw, computed } from "vue";
6
6
  import * as _ from "../../utils/dataUtils";
7
7
  import dayjs from "dayjs";
8
8
  import * as XLSX from "xlsx";
@@ -17,8 +17,10 @@ import {
17
17
  InputNumber as AInputNumber,
18
18
  message,
19
19
  } from "ant-design-vue";
20
+ import type { TableProps } from "ant-design-vue";
20
21
  import type { FormDataItem } from "../p-form/index.d";
21
22
  import type { TableColumn } from "./index.d";
23
+ import { buildTableColumns, getCellValue as getTableCellValue } from "./table-utils";
22
24
  import { useSlots } from "vue";
23
25
  const SearchFormRef = ref();
24
26
 
@@ -48,7 +50,9 @@ const {
48
50
  exportFileName = "table_export",
49
51
  } = defineProps<Props>();
50
52
 
51
- const selectedIds = defineModel<string[]>("selectedIds", { default: [] });
53
+ type RowKey = string | number;
54
+
55
+ const selectedIds = defineModel<RowKey[]>("selectedIds", { default: [] });
52
56
 
53
57
  const pageQuery = reactive({
54
58
  p: 1,
@@ -65,13 +69,15 @@ const tableData = reactive({
65
69
  },
66
70
  });
67
71
 
68
- const emits = defineEmits(["select"]);
72
+ const emits = defineEmits<{
73
+ select: [selectedRowKeys: RowKey[]];
74
+ }>();
69
75
 
70
- const rowSelection = {
76
+ const rowSelection: TableProps<any>["rowSelection"] = {
71
77
  get selectedRowKeys() {
72
78
  return selectedIds.value;
73
79
  },
74
- onChange: (selectedRowKeys: string[], _selectedRows: any[]) => {
80
+ onChange: (selectedRowKeys) => {
75
81
  selectedIds.value = selectedRowKeys;
76
82
  emits("select", selectedRowKeys);
77
83
  },
@@ -92,93 +98,23 @@ const exportForm = reactive({
92
98
  });
93
99
 
94
100
  let searchQuery = {};
101
+ let tableRequestId = 0;
95
102
 
96
- const renderTableColumns = (tableColumns: TableColumn[]) => {
97
- const returnColumns: any = [];
98
- for (const [index, renderItem] of tableColumns.entries()) {
99
- if (renderItem.type == "operate") {
100
- if (!renderItem.width) {
101
- renderItem.width = renderItem.operateButtons.length * 60;
102
- }
103
-
104
- if (editColumns.length > 0) {
105
- renderItem.width += 110;
106
- }
107
- renderItem.align = "center";
108
- }
109
-
110
- // 处理默认字段
111
- if (!_.isEmpty(renderItem.default)) {
112
- renderItem.customRender = ({ text, record }) => {
113
- return h("span", text || renderItem.default);
114
- };
115
- }
116
-
117
- // 解析json字段
118
- if (renderItem.key && renderItem.key.includes(".")) {
119
- renderItem.customRender = ({ text, record }) => {
120
- return h("span", _.get(record, renderItem.key!.split(".")));
121
- };
122
- }
123
-
124
- if (renderItem.type == "pic") {
125
- renderItem.customRender = ({ text, record }) => {
126
- const key = renderItem.key;
127
- let pics = key.includes(".") ? _.get(record, key.split(".")) : _.get(record, key);
128
- if (_.isEmpty(pics)) return h("span", "暂无");
129
- pics = _.isArray(pics) ? pics : [pics];
130
- const format_pics: any = [];
131
- for (const pic_item of pics) {
132
- if (!pic_item.includes("http") && renderItem.showOssUrlFunc) {
133
- format_pics.push(renderItem.showOssUrlFunc(pic_item));
134
- } else {
135
- format_pics.push(pic_item);
136
- }
137
- }
138
-
139
- return h(
140
- "a",
141
- {
142
- onClick: () => {
143
- viewerApi({ images: format_pics });
144
- },
145
- },
146
- h("img", {
147
- src: format_pics[0],
148
- style: {
149
- width: (renderItem.picWidth || 60) + "px",
150
- height: (renderItem.picHeight || 60) + "px",
151
- marginLeft: "10px",
152
- },
153
- }),
154
- );
155
- };
156
- }
157
-
158
- // 处理MAP字段
159
- if (renderItem.mapPath) {
160
- const mapInfoStr: any = localStorage.getItem("map");
161
- const mapInfo = JSON.parse(mapInfoStr);
162
- const mapItem = _.get(mapInfo, renderItem.mapPath);
163
- renderItem.customRender = ({ text, record }) => {
164
- return h("span", mapItem[text]);
165
- };
166
- }
167
-
168
- if (renderItem.type == "date") {
169
- renderItem.customRender = ({ text, record }) => {
170
- return h("span", dayjs(text).format(renderItem.format || "YYYY-MM-DD HH:mm:ss"));
171
- };
172
- }
173
-
174
- renderItem["dataIndex"] = renderItem["key"];
175
- returnColumns.push(renderItem);
103
+ const mapInfo = computed(() => {
104
+ try {
105
+ return JSON.parse(localStorage.getItem("map") || "{}");
106
+ } catch (error) {
107
+ return {};
176
108
  }
109
+ });
177
110
 
178
- return returnColumns;
179
- };
180
-
181
- const columns = renderTableColumns(tableColumns);
111
+ const columns = computed(() =>
112
+ buildTableColumns(tableColumns, {
113
+ editColumns,
114
+ mapInfo: mapInfo.value,
115
+ openImageViewer: (images) => viewerApi({ images }),
116
+ }),
117
+ );
182
118
 
183
119
  const getAllExportColumns = () => {
184
120
  return tableColumns.filter((item) => item.type !== "operate" && !!item.key);
@@ -213,42 +149,6 @@ const resetExportColumns = () => {
213
149
  exportForm.columns = getAllExportColumns().map((item) => String(item.key));
214
150
  };
215
151
 
216
- const getCellValue = (record: any, column: TableColumn) => {
217
- const key = column.key || "";
218
- let value = key.includes(".") ? _.get(record, key.split(".")) : _.get(record, key);
219
-
220
- if (column.mapPath) {
221
- try {
222
- const mapInfoStr: any = localStorage.getItem("map");
223
- const mapInfo = JSON.parse(mapInfoStr || "{}");
224
- const mapItem = _.get(mapInfo, column.mapPath) || {};
225
- value = mapItem[value] ?? value;
226
- } catch (error) {
227
- // ignore map parse error and fallback to raw value
228
- }
229
- }
230
-
231
- if (column.type === "date" && value) {
232
- value = dayjs(value).format(column.format || "YYYY-MM-DD HH:mm:ss");
233
- }
234
-
235
- if (column.type === "pic") {
236
- if (_.isEmpty(value)) return "";
237
- const pics = _.isArray(value) ? value : [value];
238
- value = pics.join(",");
239
- }
240
-
241
- if (_.isEmpty(value) && !_.isEmpty(column.default)) {
242
- value = column.default;
243
- }
244
-
245
- if (_.isArray(value) || (typeof value === "object" && value !== null)) {
246
- return JSON.stringify(value);
247
- }
248
-
249
- return value ?? "";
250
- };
251
-
252
152
  const downloadXlsx = (rows: any[], exportColumns: TableColumn[]) => {
253
153
  const headers = exportColumns.map((col: any) => {
254
154
  const title = col.title as any;
@@ -256,7 +156,7 @@ const downloadXlsx = (rows: any[], exportColumns: TableColumn[]) => {
256
156
  });
257
157
 
258
158
  const dataRows = rows.map((row: any) => {
259
- return exportColumns.map((col: any) => getCellValue(row, col));
159
+ return exportColumns.map((col: any) => getTableCellValue(row, col, mapInfo.value));
260
160
  });
261
161
 
262
162
  const worksheet = XLSX.utils.aoa_to_sheet([headers, ...dataRows]);
@@ -368,23 +268,26 @@ const confirmExport = async () => {
368
268
  };
369
269
 
370
270
  const renderTableData = async () => {
271
+ const requestId = ++tableRequestId;
371
272
  loading.value = true;
372
- if (getData) {
373
- const _searchInitFormData = initSearchFormData ? JSON.parse(JSON.stringify(initSearchFormData)) : {};
374
- const _pageQuery = JSON.parse(JSON.stringify(pageQuery));
375
- const _tableData = await getData({ ..._searchInitFormData, ..._pageQuery, ..._.cloneDeep(searchQuery) });
376
- tableData.data = _tableData.data;
377
- tableData.count = _tableData.count;
378
- tableData.pages = _tableData.pages;
379
- } else if (data) {
380
- tableData.data = data;
273
+ try {
274
+ if (getData) {
275
+ const _searchInitFormData = initSearchFormData ? JSON.parse(JSON.stringify(initSearchFormData)) : {};
276
+ const _pageQuery = JSON.parse(JSON.stringify(pageQuery));
277
+ const _tableData = await getData({ ..._searchInitFormData, ..._pageQuery, ..._.cloneDeep(searchQuery) });
278
+ if (requestId !== tableRequestId) return;
279
+ tableData.data = _tableData.data;
280
+ tableData.count = _tableData.count;
281
+ tableData.pages = _tableData.pages;
282
+ } else if (data) {
283
+ tableData.data = data;
284
+ tableData.count = data.length;
285
+ }
286
+ } finally {
287
+ if (requestId === tableRequestId) {
288
+ loading.value = false;
289
+ }
381
290
  }
382
-
383
- tableData.data.forEach((item, index) => {
384
- item["index"] = index;
385
- });
386
-
387
- loading.value = false;
388
291
  };
389
292
 
390
293
  const refresh = () => {
@@ -441,16 +344,20 @@ const getTableData = () => {
441
344
  return toRaw(tableData)["data"];
442
345
  };
443
346
 
444
- const edit = (index: string) => {
445
- editableData[index] = _.cloneDeep(tableData.data[index]);
347
+ const getRowEditKey = (record: any, index: number) => record?.id ?? index;
348
+
349
+ const edit = (record: any, index: number) => {
350
+ editableData[getRowEditKey(record, index)] = _.cloneDeep(record);
446
351
  };
447
- const save = (key: string) => {
448
- Object.assign(tableData.data.filter((item) => key === item.key)[0], editableData[key]);
352
+
353
+ const save = (record: any, index: number) => {
354
+ const key = getRowEditKey(record, index);
355
+ Object.assign(record, editableData[key]);
449
356
  delete editableData[key];
450
357
  };
451
358
 
452
- const cancel = (key: string) => {
453
- delete editableData[key];
359
+ const cancel = (record: any, index: number) => {
360
+ delete editableData[getRowEditKey(record, index)];
454
361
  };
455
362
 
456
363
  onMounted(() => {
@@ -474,8 +381,8 @@ defineExpose({
474
381
  layout="inline"
475
382
  >
476
383
  <template v-slot:button>
477
- <a-button type="primary" @click="searchClick" @keydown.enter.prevent="searchClick" style="margin-left: 20px"> 搜索 </a-button>
478
- <a-button style="margin-left: 10px" @click="resetSearch" @keydown.enter.prevent="resetSearch"> 重置 </a-button>
384
+ <a-button type="primary" @click="searchClick" style="margin-left: 20px"> 搜索 </a-button>
385
+ <a-button style="margin-left: 10px" @click="resetSearch"> 重置 </a-button>
479
386
  </template>
480
387
  </PForm>
481
388
  </div>
@@ -485,7 +392,7 @@ defineExpose({
485
392
  style="display: flex; justify-content: flex-end; gap: 10px; margin-bottom: 10px; padding: 20px"
486
393
  >
487
394
  <slot name="button"></slot>
488
- <a-button v-if="enableExport" type="primary" @click="openExportModal" @keydown.enter.prevent="openExportModal">导出Excel</a-button>
395
+ <a-button v-if="enableExport" type="primary" @click="openExportModal">导出Excel</a-button>
489
396
  </div>
490
397
 
491
398
  <a-table
@@ -514,8 +421,8 @@ defineExpose({
514
421
  <template v-if="editColumns.includes(column.key as string)">
515
422
  <div>
516
423
  <a-textarea
517
- v-if="editableData[record.index]"
518
- v-model:value="editableData[record.index][column.key]"
424
+ v-if="editableData[getRowEditKey(record, index)]"
425
+ v-model:value="editableData[getRowEditKey(record, index)][column.key]"
519
426
  style="margin: -5px 0"
520
427
  :auto-size="true"
521
428
  />
@@ -532,16 +439,13 @@ defineExpose({
532
439
  v-if="!item.visibleFunc || (item.visibleFunc && item.visibleFunc(record))"
533
440
  class="operate-a"
534
441
  @click="item.click(record)"
535
- @keydown.enter.prevent="item.click(record)"
536
- tabindex="0"
537
- role="button"
538
442
  >
539
443
  {{ item.label }}</a
540
444
  >
541
445
  </span>
542
- <a class="operate-a" v-if="editableData[record.index]" @click="save(record.index)" @keydown.enter.prevent="save(record.index)" tabindex="0" role="button">保存</a>
543
- <a class="operate-a" v-if="editableData[record.index]" @click="cancel(record.index)" @keydown.enter.prevent="cancel(record.index)" tabindex="0" role="button">退出</a>
544
- <a v-if="editColumns.length > 0" class="operate-a" @click="edit(record.index)" @keydown.enter.prevent="edit(record.index)" tabindex="0" role="button">编辑</a>
446
+ <a class="operate-a" v-if="editableData[getRowEditKey(record, index)]" @click="save(record, index)">保存</a>
447
+ <a class="operate-a" v-if="editableData[getRowEditKey(record, index)]" @click="cancel(record, index)">退出</a>
448
+ <a v-if="editColumns.length > 0" class="operate-a" @click="edit(record, index)">编辑</a>
545
449
  </div>
546
450
  </template>
547
451
 
@@ -0,0 +1,115 @@
1
+ import { h } from "vue";
2
+ import dayjs from "dayjs";
3
+ import type { TableColumn } from "./index.d";
4
+ import * as _ from "../../utils/dataUtils";
5
+
6
+ type BuildTableColumnOptions = {
7
+ editColumns?: string[];
8
+ mapInfo?: any;
9
+ openImageViewer?: (images: string[]) => void;
10
+ };
11
+
12
+ export const getColumnValue = (record: any, key?: string) => {
13
+ if (!key) return undefined;
14
+ return key.includes(".") ? _.get(record, key.split(".")) : _.get(record, key);
15
+ };
16
+
17
+ export const getCellValue = (record: any, column: TableColumn, mapInfo: any = {}) => {
18
+ const key = column.key || "";
19
+ let value = getColumnValue(record, key);
20
+
21
+ if (column.mapPath) {
22
+ const mapItem = _.get(mapInfo || {}, column.mapPath) || {};
23
+ value = mapItem[value] ?? value;
24
+ }
25
+
26
+ if (column.type === "date" && value) {
27
+ value = dayjs(value).format(column.format || "YYYY-MM-DD HH:mm:ss");
28
+ }
29
+
30
+ if (column.type === "pic") {
31
+ if (_.isEmpty(value)) return "";
32
+ const pics = _.isArray(value) ? value : [value];
33
+ return pics.join(",");
34
+ }
35
+
36
+ if (_.isEmpty(value) && !_.isEmpty(column.default)) {
37
+ value = column.default;
38
+ }
39
+
40
+ if (_.isArray(value) || (typeof value === "object" && value !== null)) {
41
+ return JSON.stringify(value);
42
+ }
43
+
44
+ return value ?? "";
45
+ };
46
+
47
+ export const buildTableColumns = (tableColumns: TableColumn[], options: BuildTableColumnOptions = {}) => {
48
+ const { editColumns = [], mapInfo = {}, openImageViewer } = options;
49
+
50
+ return tableColumns.map((column) => {
51
+ const renderItem: any = { ...column };
52
+
53
+ if (renderItem.type === "operate") {
54
+ renderItem.width = renderItem.width || renderItem.operateButtons.length * 60;
55
+
56
+ if (editColumns.length > 0) {
57
+ renderItem.width += 110;
58
+ }
59
+
60
+ renderItem.align = "center";
61
+ }
62
+
63
+ if (!_.isEmpty(renderItem.default)) {
64
+ renderItem.customRender = ({ text }: any) => h("span", text || renderItem.default);
65
+ }
66
+
67
+ if (renderItem.key && renderItem.key.includes(".")) {
68
+ renderItem.customRender = ({ record }: any) => h("span", getColumnValue(record, renderItem.key));
69
+ }
70
+
71
+ if (renderItem.type === "pic") {
72
+ renderItem.customRender = ({ record }: any) => {
73
+ let pics = getColumnValue(record, renderItem.key);
74
+ if (_.isEmpty(pics)) return h("span", "暂无");
75
+
76
+ pics = _.isArray(pics) ? pics : [pics];
77
+ const formatPics = pics.map((picItem: string) => {
78
+ if (!picItem.includes("http") && renderItem.showOssUrlFunc) {
79
+ return renderItem.showOssUrlFunc(picItem);
80
+ }
81
+
82
+ return picItem;
83
+ });
84
+
85
+ return h(
86
+ "a",
87
+ {
88
+ onClick: () => openImageViewer?.(formatPics),
89
+ },
90
+ h("img", {
91
+ src: formatPics[0],
92
+ style: {
93
+ width: `${renderItem.picWidth || 60}px`,
94
+ height: `${renderItem.picHeight || 60}px`,
95
+ marginLeft: "10px",
96
+ },
97
+ }),
98
+ );
99
+ };
100
+ }
101
+
102
+ if (renderItem.mapPath) {
103
+ const mapItem = _.get(mapInfo || {}, renderItem.mapPath) || {};
104
+ renderItem.customRender = ({ text }: any) => h("span", mapItem[text] ?? text ?? "");
105
+ }
106
+
107
+ if (renderItem.type === "date") {
108
+ renderItem.customRender = ({ text }: any) =>
109
+ h("span", text ? dayjs(text).format(renderItem.format || "YYYY-MM-DD HH:mm:ss") : "");
110
+ }
111
+
112
+ renderItem.dataIndex = renderItem.key;
113
+ return renderItem;
114
+ });
115
+ };
package/dist/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ declare module "*.vue" {
2
+ import type { DefineComponent } from "vue";
3
+
4
+ const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, any>;
5
+ export default component;
6
+ }
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "p-pc-ui",
3
- "version": "1.3.12",
4
- "type": "module",
3
+ "version": "1.3.14",
5
4
  "module": "dist/index.ts",
6
5
  "main": "dist/index.ts",
7
6
  "files": [