plain-design 1.0.0-beta.131 → 1.0.0-beta.132

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.
Files changed (44) hide show
  1. package/dist/plain-design.commonjs.min.js +2 -2
  2. package/dist/plain-design.min.css +5 -4
  3. package/dist/plain-design.min.js +2 -2
  4. package/dist/report.html +2 -2
  5. package/package.json +1 -1
  6. package/src/packages/components/AutoTable/auto-table.scss +21 -0
  7. package/src/packages/components/AutoTable/filter/useTableOption.filter.state.ts +3 -2
  8. package/src/packages/components/AutoTable/use/useTableOption.column.popper.tsx +1 -1
  9. package/src/packages/components/AutoTable/use/useTableOption.fill.tsx +2 -2
  10. package/src/packages/components/AutoTable/use/useTableOption.hooks.tsx +4 -2
  11. package/src/packages/components/AutoTable/use/useTableOption.pagination.tsx +1 -1
  12. package/src/packages/components/AutoTable/use/useTableOption.table.tsx +5 -3
  13. package/src/packages/components/AutoTable/use/useTableOption.tips.tsx +2 -2
  14. package/src/packages/components/AutoTable/utils/TableOption.space.tsx +5 -2
  15. package/src/packages/components/Dropdown/index.tsx +14 -1
  16. package/src/packages/components/Form/form.scss +4 -0
  17. package/src/packages/components/Form/layout/useFormLayout.tsx +1 -0
  18. package/src/packages/components/FormItem/index.tsx +7 -0
  19. package/src/packages/components/Input/useSuggestionInput.tsx +2 -1
  20. package/src/packages/components/ListOption/index.tsx +20 -0
  21. package/src/packages/components/ListPanel/index.tsx +30 -0
  22. package/src/packages/components/ListPanel/list-panel.scss +20 -0
  23. package/src/packages/components/Select/createPublicSelectRender.tsx +4 -2
  24. package/src/packages/components/Select/decodeSelectRenderNode.tsx +4 -2
  25. package/src/packages/components/Select/index.tsx +13 -1
  26. package/src/packages/components/Select/select.utils.tsx +3 -2
  27. package/src/packages/components/Table/plc/use/useTableAutoSpan.tsx +112 -0
  28. package/src/packages/components/Table/plc/utils/plc.utils.ts +3 -0
  29. package/src/packages/components/Table/standard/PlcOperation/PlcOperation.tsx +3 -3
  30. package/src/packages/components/Table/table/Table.tsx +10 -6
  31. package/src/packages/components/Table/table/body/cell.tsx +34 -3
  32. package/src/packages/components/Table/table/body/useCellValue.tsx +14 -5
  33. package/src/packages/components/Table/table/head/head-cell.tsx +6 -0
  34. package/src/packages/components/Table/table/table.scss +4 -0
  35. package/src/packages/components/Table/table/use/useTableFormEditor.tsx +5 -1
  36. package/src/packages/components/Table/table/use/useTableModifyEditor.tsx +8 -2
  37. package/src/packages/components/Table/table/utils/createTableHooks.ts +5 -3
  38. package/src/packages/components/Table/table/utils/table.utils.ts +3 -2
  39. package/src/packages/components/VirtualTable/index.tsx +6 -0
  40. package/src/packages/components/VirtualTable/virtual-table.scss +3 -3
  41. package/src/packages/components/createSimpleDate/index.ts +49 -0
  42. package/src/packages/components/useContextmenuOptions/index.tsx +40 -0
  43. package/src/packages/components/useTableFilter/index.ts +73 -0
  44. package/src/packages/entry.tsx +6 -0
@@ -245,14 +245,18 @@ export const Table = designComponent({
245
245
  ),
246
246
  });
247
247
 
248
- hooks.onClickCell.use(({ e, node }) => {
249
- event.emit.onClickCell(node, e);
250
- hooks.onClickRow.exec({ e, node });
248
+ hooks.onClickCell.use((val) => {
249
+ event.emit.onClickCell(val.node, val.e, val.plc);
250
+ hooks.onClickRow.exec({ e: val.e, node: val.node });
251
251
  });
252
252
 
253
- hooks.onDblclickCell.use(({ e, node }) => {
254
- event.emit.onDblclickCell(node, e);
255
- hooks.onDblclickRow.exec({ e, node });
253
+ hooks.onDblclickCell.use((val) => {
254
+ event.emit.onDblclickCell(val.node, val.e, val.plc);
255
+ hooks.onDblclickRow.exec({ e: val.e, node: val.node });
256
+ });
257
+
258
+ hooks.onContextmenuCell.use((val) => {
259
+ event.emit.onContextmenuCell(val.node, val.e, val.plc);
256
260
  });
257
261
 
258
262
  hooks.onClickHeadCell.use(({ e, plc }) => {!plc.props.disableAutoEmitClickTitle && event.emit.onClickHead(plc, e);});
@@ -10,6 +10,7 @@ import {useCellValue} from "./useCellValue";
10
10
  import {createTooltip} from "../../../useTooltip";
11
11
  import {createEffects} from "@peryl/utils/createEffects";
12
12
  import {usePopup} from "../../../usePopup";
13
+ import {injectTableAutoSpan} from "../../plc/use/useTableAutoSpan";
13
14
 
14
15
  export const PltCell = designComponent({
15
16
  name: 'plt-cell',
@@ -23,6 +24,9 @@ export const PltCell = designComponent({
23
24
  const { refs, onRef } = useRefs({ el: iHTMLElement });
24
25
 
25
26
  const popup = usePopup();
27
+
28
+ const tableAutoSpan = injectTableAutoSpan();
29
+
26
30
  /**
27
31
  * 单元格校验
28
32
  * @author 韦胜健
@@ -51,6 +55,11 @@ export const PltCell = designComponent({
51
55
  props.table.hooks.onDblclickCell.exec({ e, node: props.node, plc: props.plc });
52
56
  };
53
57
 
58
+ const onContextmenu = (e: iMouseEvent) => {
59
+ // if (bodyCell.value().editable) {return;}
60
+ props.table.hooks.onContextmenuCell.exec({ e, node: props.node, plc: props.plc });
61
+ };
62
+
54
63
  /**
55
64
  * 鼠标进入单元格
56
65
  * @author 韦胜健
@@ -70,7 +79,9 @@ export const PltCell = designComponent({
70
79
  * @author 韦胜健
71
80
  * @date 2022/12/5 20:35
72
81
  */
73
- const { bodyCell } = useCellValue({ optionGetter: () => ({ node: props.node, plc: props.plc }), formEdit: false });
82
+ const { effects: cellValueEffects } = createEffects();
83
+ onBeforeUnmount(() => cellValueEffects.clear());
84
+ const { bodyCell } = useCellValue({ optionGetter: () => ({ node: props.node, plc: props.plc }), formEdit: false, effects: cellValueEffects });
74
85
 
75
86
  /**
76
87
  * 单元格样式类名
@@ -143,7 +154,7 @@ export const PltCell = designComponent({
143
154
  * 则不显示overflowTooltip
144
155
  */
145
156
  if (!props.plc.props.overflowTooltip || !bodyCell || bodyCell.editable) {
146
- return emptyOverflowTooltipOption
157
+ return emptyOverflowTooltipOption;
147
158
  } else {
148
159
  return {
149
160
  reference: !props.plc.props.overflowTooltip || !bodyCell || bodyCell.editable ? null : refs.el,
@@ -182,14 +193,32 @@ export const PltCell = designComponent({
182
193
  return { update };
183
194
  })();
184
195
 
196
+ /*每次渲染都记录上一次的span,某次渲染在offsetData中找不到自己的offsetIndex时,就用上一次的span*/
197
+ let prevSpan = { rowspan: 1, colspan: 1 };
198
+
185
199
  return {
186
200
  render: () => {
187
201
  const { node, plc } = props;
188
202
  const { body, editable } = bodyCell.value();
189
- const span = !!props.table.props.spanMethod ? props.table.props.spanMethod({ node, plc }) : { rowspan: 1, colspan: 1 };
203
+ let span = !!props.table.props.spanMethod ? props.table.props.spanMethod({ node, plc }) : { rowspan: 1, colspan: 1 };
190
204
  if (plc.props.editColSpan != null && node.state.edit) {
191
205
  span.colspan = typeof plc.props.editColSpan === "function" ? plc.props.editColSpan(node) : plc.props.editColSpan;
192
206
  }
207
+ if (!!tableAutoSpan.value && (plc.props.autoRowSpan || plc.props.autoColSpan)) {
208
+ const { spans, data: offsetData } = tableAutoSpan.value;
209
+ /*要用offsetIndex,而不是props.node.state.index,这个是行数据在所有数据中的真实索引,而不是在虚拟列表数据中的索引*/
210
+ /*计算的spans仅含有虚拟数据的合并结果*/
211
+ const offsetIndex = offsetData.indexOf(props.node.data);
212
+ if (offsetIndex > -1) {
213
+ const rowSpan = !plc.props.field ? null : spans[offsetIndex].row?.[plc.props.field];
214
+ if (rowSpan != null) {span.rowspan = rowSpan;}
215
+ const colSpan = !plc.props.field ? null : spans[offsetIndex].col?.[plc.props.field];
216
+ if (colSpan != null) {span.colspan = colSpan;}
217
+ } else {
218
+ span = prevSpan;
219
+ }
220
+ }
221
+ prevSpan = span;
193
222
  if (span.rowspan === 0 || span.colspan === 0) {
194
223
  /*rowspan为0时,不会正确合并单元格,如果要合并单元格则不渲染这个td*/
195
224
  return null;
@@ -201,6 +230,7 @@ export const PltCell = designComponent({
201
230
  // console.log('cell', props.plc.props.title);
202
231
  return (
203
232
  <td
233
+ data-span={String(span.rowspan != 1 || span.colspan != 1)}
204
234
  ref={onRef.el}
205
235
  rowSpan={span.rowspan}
206
236
  colSpan={span.colspan}
@@ -208,6 +238,7 @@ export const PltCell = designComponent({
208
238
  style={styles.value}
209
239
  onClick={onClick}
210
240
  onDoubleClick={onDblclick}
241
+ onContextMenu={onContextmenu}
211
242
  onMouseEnter={onEnter}
212
243
  onMouseLeave={onLeave}
213
244
  >
@@ -1,11 +1,13 @@
1
1
  import {iTableNode} from "../utils/table.utils";
2
2
  import {tPlc} from "../../plc/utils/plc.utils";
3
- import {computed, reactive, toRaw} from "@peryl/react-compose";
3
+ import {globalComputed, reactive, toRaw} from "@peryl/react-compose";
4
4
  import {PlainObject} from "@peryl/utils/event";
5
5
  import {LoadingText} from "../../../../utils/LoadingText";
6
6
  import {AsyncFormatter} from "../../../AsyncFormatter";
7
7
  import {Formatter} from "../../../Formatter";
8
8
  import {renderBodyCell} from "../../plc/utils/plc.render";
9
+ import {iEffects} from "@peryl/utils/createEffects";
10
+ import {delay} from "@peryl/utils/delay";
9
11
 
10
12
  /**
11
13
  * 计算cell渲染所需要的内容
@@ -16,9 +18,11 @@ export function useCellValue(
16
18
  {
17
19
  optionGetter,
18
20
  formEdit,
21
+ effects,
19
22
  }: {
20
23
  optionGetter: () => { node: iTableNode, plc: tPlc },
21
24
  formEdit: boolean,
25
+ effects: iEffects,
22
26
  }
23
27
  ) {
24
28
  /**
@@ -26,20 +30,22 @@ export function useCellValue(
26
30
  * @author 韦胜健
27
31
  * @date 2022.12.3 10:50
28
32
  */
29
- const row = computed(() => {
33
+ const row = globalComputed(() => {
30
34
  const { node } = optionGetter();
31
35
  return node.state.edit ? node.state.editRow : node.data;
32
36
  });
37
+ effects.push(() => row.effect.stop());
33
38
 
34
39
  /**
35
40
  * 当前单元格的目标数据
36
41
  * @author 韦胜健
37
42
  * @date 2022.12.3 10:50
38
43
  */
39
- const sourceValue = computed(() => {
44
+ const sourceValue = globalComputed(() => {
40
45
  const { plc } = optionGetter();
41
46
  return !!plc.props.field ? row.value[plc.props.field] : null;
42
47
  });
48
+ effects.push(() => sourceValue.effect.stop());
43
49
 
44
50
  /**
45
51
  * 异步格式化的状态
@@ -58,8 +64,9 @@ export function useCellValue(
58
64
  loading: boolean,
59
65
  }
60
66
  });
67
+ effects.push(() => delay().then(() => {asyncState.asyncValue = null;}));
61
68
 
62
- const targetValue = computed(() => {
69
+ const targetValue = globalComputed(() => {
63
70
  const { plc, node } = optionGetter();
64
71
  const { formatter, asyncFormatter, formatterOptions } = plc.props;
65
72
  const cellRenderScope = { plc: plc, node: node, row: row.value };
@@ -125,12 +132,14 @@ export function useCellValue(
125
132
  return sourceValue.value;
126
133
  }
127
134
  });
135
+ effects.push(() => targetValue.effect.stop());
128
136
 
129
- const bodyCell = computed(() => {
137
+ const bodyCell = globalComputed(() => {
130
138
  const { node, plc } = optionGetter();
131
139
  const bc = renderBodyCell({ node, plc, formEdit, targetValue: targetValue.value });
132
140
  return () => bc;
133
141
  });
142
+ effects.push(() => bodyCell.effect.stop());
134
143
 
135
144
  return { bodyCell, targetValue };
136
145
  }
@@ -7,6 +7,8 @@ import {PlainScroll} from "../../../Scroll";
7
7
  import {Icon} from "../../../Icon";
8
8
  import {renderHeadCell} from "../../plc/utils/plc.render";
9
9
  import {useTooltip} from "../../../useTooltip";
10
+ import Tooltip from "../../../Tooltip";
11
+ import {getFunctionValue} from '@peryl/utils/getFunctionValue';
10
12
 
11
13
  export const PltHeadCell = designComponent({
12
14
  name: 'plt-head-cell',
@@ -77,6 +79,10 @@ export const PltHeadCell = designComponent({
77
79
  onMouseLeave={handler.onLeave}
78
80
  >
79
81
  {content}
82
+ {!!props.tablePlc.props.tip && <Tooltip v-slots={{
83
+ default: () => <Icon icon="pi-info-circle" className="plt-head-cell-tip"/>,
84
+ popper: () => getFunctionValue(props.tablePlc.props.tip)
85
+ }}/>}
80
86
  <span className="plt-head-cell-indicator" onMouseDown={resizeHandler.mousedown}/>
81
87
  {sort.value != null && (
82
88
  <div className={`plt-head-cell-sorter plt-head-cell-sorter-${sort.value ? 'desc' : 'asc'}`}>
@@ -24,6 +24,10 @@
24
24
  font-weight: 500;
25
25
  letter-spacing: 1px;
26
26
 
27
+ .plt-head-cell-tip {
28
+ color: plv(text-3);
29
+ }
30
+
27
31
  .plt-head-cell-indicator {
28
32
  position: absolute;
29
33
  top: 0;
@@ -53,10 +53,13 @@ export function useTableFormEditor(
53
53
  * @author 韦胜健
54
54
  * @date 2022/12/5 20:45
55
55
  */
56
+ const { effects: cellBodyArrayEffects } = createEffects();
57
+ effects.push(() => cellBodyArrayEffects.clear());
56
58
  const cellBodyArray = computed(() => {
59
+ cellBodyArrayEffects.clear();
57
60
  if (!state.optionGetter) {return [];}
58
61
  const { node } = state.optionGetter();
59
- return showPlcArray.value.map(plc => useCellValue({ optionGetter: () => ({ plc, node }), formEdit: true }));
62
+ return showPlcArray.value.map(plc => useCellValue({ optionGetter: () => ({ plc, node }), formEdit: true, effects: cellBodyArrayEffects }));
60
63
  });
61
64
 
62
65
  const handler = {
@@ -136,6 +139,7 @@ export function useTableFormEditor(
136
139
  required={plc.props.required}
137
140
  rules={plc.props.rules}
138
141
  validator={plc.props.validator}
142
+ tip={plc.props.tip}
139
143
  disabled={!editable}
140
144
  {...validateAttrs}
141
145
  >
@@ -3,7 +3,7 @@ import {iTableHooks} from "../utils/createTableHooks";
3
3
  import {PlcValidatePropsOption, tPlc} from "../../plc/utils/plc.utils";
4
4
  import {createEffects} from "@peryl/utils/createEffects";
5
5
  import {PlainObject} from "@peryl/utils/event";
6
- import {computed, reactive, RenderNode, useRefs} from "@peryl/react-compose";
6
+ import {computed, onBeforeUnmount, reactive, RenderNode, useRefs} from "@peryl/react-compose";
7
7
  import {Dialog} from "../../../Dialog";
8
8
  import {delay} from "@peryl/utils/delay";
9
9
  import {Table} from "../Table";
@@ -64,11 +64,13 @@ export function useTableModifyEditor(
64
64
  * @author 韦胜健
65
65
  * @date 2022/12/5 20:45
66
66
  */
67
+ const { effects: cellBodyArrayEffects } = createEffects();
68
+ effects.push(() => cellBodyArrayEffects.clear());
67
69
  const cellBodyArray = computed(() => {
68
70
  if (!state.optionGetter) {return [];}
69
71
  const { node } = state;
70
72
  if (!node) {return [];}
71
- return availablePlcList.value.map(i => useCellValue({ optionGetter: () => ({ plc: i.getPlc(), node }), formEdit: true }));
73
+ return availablePlcList.value.map(i => useCellValue({ optionGetter: () => ({ plc: i.getPlc(), node }), formEdit: true, effects: cellBodyArrayEffects }));
72
74
  });
73
75
 
74
76
  const handler = {
@@ -124,6 +126,7 @@ export function useTableModifyEditor(
124
126
  required={plc.props.required}
125
127
  rules={plc.props.rules}
126
128
  validator={plc.props.validator}
129
+ tip={plc.props.tip}
127
130
  disabled={!editable}
128
131
  {...validateAttrs}
129
132
  >
@@ -142,6 +145,7 @@ export function useTableModifyEditor(
142
145
  initialize: (() => {
143
146
  let hasInitialized = false;
144
147
  return () => {
148
+ /*已经初始化过就不用再初始化了*/
145
149
  if (hasInitialized) {return;}
146
150
  hasInitialized = true;
147
151
  effects.push(hooks.onRender.use(
@@ -187,6 +191,8 @@ export function useTableModifyEditor(
187
191
  },
188
192
  };
189
193
 
194
+ onBeforeUnmount(() => effects.clear());
195
+
190
196
  return { methods, state };
191
197
  }
192
198
 
@@ -1,5 +1,5 @@
1
1
  import {createHooks, createRenderHook, createSyncHooks, iMouseEvent, RenderNode, StyleProperties} from "@peryl/react-compose";
2
- import {tPlcType} from "../../plc/utils/plc.utils";
2
+ import {tPlc, tPlcType} from "../../plc/utils/plc.utils";
3
3
  import {iTableMessyData, iTableNode} from "./table.utils";
4
4
  import {PlainObject} from "@peryl/utils/event";
5
5
  import {VirtualTable} from "../../../VirtualTable";
@@ -25,9 +25,11 @@ export const createTableHooks = () => {
25
25
  /*双击行动作*/
26
26
  onDblclickRow: createHooks<(data: { e: iMouseEvent, node: iTableNode }) => void>(),
27
27
  /*单击单元格动作*/
28
- onClickCell: createHooks<(data: { e: iMouseEvent, node: iTableNode, plc: tPlcType }) => void>(),
28
+ onClickCell: createHooks<(data: { e: iMouseEvent, node: iTableNode, plc: tPlc }) => void>(),
29
29
  /*双击单元格动作*/
30
- onDblclickCell: createHooks<(data: { e: iMouseEvent, node: iTableNode, plc: tPlcType }) => void>(),
30
+ onDblclickCell: createHooks<(data: { e: iMouseEvent, node: iTableNode, plc: tPlc }) => void>(),
31
+ /*右击单元格动作*/
32
+ onContextmenuCell: createHooks<(data: { e: iMouseEvent, node: iTableNode, plc: tPlc }) => void>(),
31
33
  /*鼠标进入单元格*/
32
34
  onEnterCell: createHooks<(data: { e: iMouseEvent, node: iTableNode, plc: tPlcType }) => void>(),
33
35
  /*鼠标离开单元格*/
@@ -93,8 +93,9 @@ export const TableEmitsOptions = {
93
93
 
94
94
  onClickRow: (node: iTableNode, e: iMouseEvent) => true,
95
95
  onDblclickRow: (node: iTableNode, e: iMouseEvent) => true,
96
- onClickCell: (node: iTableNode, e: iMouseEvent) => true,
97
- onDblclickCell: (node: iTableNode, e: iMouseEvent) => true,
96
+ onClickCell: (node: iTableNode, e: iMouseEvent, plc: tPlc) => true,
97
+ onDblclickCell: (node: iTableNode, e: iMouseEvent, plc: tPlc) => true,
98
+ onContextmenuCell: (node: iTableNode, e: iMouseEvent, plc: tPlc) => true,
98
99
  onClickHead: (plc: tPlcType, e: iMouseEvent) => true,
99
100
 
100
101
  onConfigPlc: (data: { plcList: tPlcType[], stateData: tPlcCacheStateData }) => true,
@@ -7,6 +7,8 @@ import './virtual-table.scss';
7
7
  import i18n from "../i18n";
8
8
  import {doNothing} from "@peryl/utils/doNothing";
9
9
  import {useWatchAutoClear} from "../../utils/watchEffectAutoClear";
10
+ import {useTableAutoSpan} from "../Table/plc/use/useTableAutoSpan";
11
+ import {iTableNode} from "../Table/table/utils/table.utils";
10
12
 
11
13
  export const VirtualTable = designComponent({
12
14
  name: 'virtual-table',
@@ -55,6 +57,8 @@ export const VirtualTable = designComponent({
55
57
  /*虚拟滚动时让出顶部距离显示表头*/
56
58
  const { virtual } = useVirtualList({ dataModel, props, refs: refs as any, emit, transform: false });
57
59
 
60
+ const tableAutoSpan = useTableAutoSpan(() => ({ data: virtual.offsetData.value.list.map(i => (i.item as iTableNode).data) }));
61
+
58
62
  /*---------------------------------------computed-------------------------------------------*/
59
63
  const styles = useStyles(style => {
60
64
  style.height = unit(props.height);
@@ -154,6 +158,8 @@ export const VirtualTable = designComponent({
154
158
  },
155
159
  render: () => {
156
160
  const { list } = virtual.offsetData.value;
161
+ /*触发响应式计算*/
162
+ doNothing(tableAutoSpan.value?.spans);
157
163
  return (
158
164
  <div style={styles.value} className={classes.value}>
159
165
  <Scroll
@@ -81,19 +81,19 @@ $scrollbarSize: 12px;
81
81
  }
82
82
 
83
83
  &:hover {
84
- td {
84
+ td:not([data-span=true]) {
85
85
  background-color: plv(table-row-hover-color);
86
86
  }
87
87
  }
88
88
 
89
89
  &.plt-row-current {
90
- td {
90
+ td:not([data-span=true]) {
91
91
  background-color: plv(table-row-current-color);
92
92
  }
93
93
  }
94
94
 
95
95
  &.plt-row-checked {
96
- td {
96
+ td:not([data-span=true]) {
97
97
  background-color: plv(primary-light-1);
98
98
  border-bottom-color: plv(primary-light-2);
99
99
  }
@@ -0,0 +1,49 @@
1
+ export function createSimpleDate(_date?: Date) {
2
+ const date = _date || new Date();
3
+ const year = date.getFullYear();
4
+ const month = date.getMonth() + 1;
5
+ const day = date.getDate();
6
+ const hour = date.getHours();
7
+ const minute = date.getMinutes();
8
+ const second = date.getSeconds();
9
+
10
+ const YYYY = String(year);
11
+ const MM = String(month).padStart(2, '0');
12
+ const DD = String(day).padStart(2, '0');
13
+ const HH = String(hour).padStart(2, '0');
14
+ const mm = String(minute).padStart(2, '0');
15
+ const ss = String(second).padStart(2, '0');
16
+
17
+ return {
18
+ 'YYYY-MM-DD HH:mm:ss': `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`,
19
+ 'YYYY-MM-DD': `${YYYY}-${MM}-${DD}`,
20
+ 'HH:mm:ss': `${HH}:${mm}:${ss}`,
21
+ YMDHms: Number(`${YYYY}${MM}${DD}${HH}${mm}${ss}`),
22
+ YMD: Number(`${YYYY}${MM}${DD}`),
23
+ };
24
+ }
25
+
26
+ export const parseDateString = (dateString: string): Date | null => {
27
+ const match = /(\d\d\d\d)-(\d\d)-(\d\d)/.exec(dateString);
28
+ if (!match) {return null;}
29
+ const year = Number(match[1]);
30
+ const month = Number(match[2]);
31
+ const date = Number(match[3]);
32
+ return new Date(year, month - 1, date);
33
+ };
34
+
35
+ export const parseDatetimeString = (datetimeString: string) => {
36
+ const match = /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/.exec(datetimeString);
37
+ if (!match) {return null;}
38
+ const year = Number(match[1]);
39
+ const month = Number(match[2]);
40
+ const date = Number(match[3]);
41
+ const hour = Number(match[4]);
42
+ const minute = Number(match[5]);
43
+ const second = Number(match[6]);
44
+ return new Date(year, month - 1, date, hour, minute, second);
45
+ };
46
+
47
+ export const nowDate = () => createSimpleDate()['YYYY-MM-DD'];
48
+ export const nowTime = () => createSimpleDate()['HH:mm:ss'];
49
+ export const nowDatetime = () => createSimpleDate()['YYYY-MM-DD HH:mm:ss'];
@@ -0,0 +1,40 @@
1
+ import {usePopup} from "../usePopup";
2
+ import {ListPanel} from "../ListPanel";
3
+ import {ListOption} from "../ListOption";
4
+ import {iMouseEvent} from "@peryl/react-compose";
5
+ import {getFunctionValue} from "@peryl/utils/getFunctionValue";
6
+
7
+ export const useContextmenuOptions = () => {
8
+
9
+ const { $popup } = usePopup();
10
+
11
+ const open = ({ x, y ,options}: { x: number, y: number, options: iContextmenuOption[]}) => {
12
+ const pop = $popup.absolute({
13
+ x, y,
14
+ noArrow: true,
15
+ noPadding: true,
16
+ type: 'contextmenu-option',
17
+ placement: 'bottom-start',
18
+ trigger: 'contextmenu',
19
+ render: () => (
20
+ <ListPanel>
21
+ {options.map((option, index) => (
22
+ <ListOption key={index} label="管理该类型" onClick={async (e) => {
23
+ const flag = await option.handler(e);
24
+ if (flag != false) {pop.hide();}
25
+ }}>
26
+ {getFunctionValue(option.label)}
27
+ </ListOption>
28
+ ))}
29
+ </ListPanel>
30
+ )
31
+ });
32
+ };
33
+
34
+ return { open };
35
+ };
36
+
37
+ export interface iContextmenuOption {
38
+ label: string | (() => any);
39
+ handler: (e: iMouseEvent) => void | boolean | Promise<void | boolean>,
40
+ }
@@ -0,0 +1,73 @@
1
+ import {TableOptionSpace} from "../AutoTable/utils/TableOption.space";
2
+ import {computed, reactive, RenderNode} from "@peryl/react-compose";
3
+ import {iFilterQueryParam} from "../FilterService/utils/filter.service.utils";
4
+
5
+ export function useTableFilter<T>(
6
+ {
7
+ modelValue,
8
+ option,
9
+ defaultValue,
10
+ display,
11
+ handleClickTip,
12
+ handleClear,
13
+ getQueryParam,
14
+ noClear,
15
+ }: {
16
+ option: TableOptionSpace.iTableOption,
17
+ display: (val: T) => RenderNode,
18
+ getQueryParam: (val: T) => iFilterQueryParam,
19
+ modelValue?: { set: (newVal: T | null) => void, get: () => T | null },
20
+ defaultValue?: T,
21
+ handleClickTip?: (val: T) => void,
22
+ handleClear?: (val: T) => void,
23
+ noClear?: boolean,
24
+ }) {
25
+
26
+ const model = (() => {
27
+ const _modelValue = modelValue || (() => {
28
+ const state = reactive({ value: defaultValue });
29
+ return { get: (): T | null => state.value as any, set: (newVal: T | null) => {state.value = newVal as any;} };
30
+ })();
31
+ return {
32
+ get: () => _modelValue.get(),
33
+ set: (newVal: T | null) => {_modelValue.set(newVal);}
34
+ };
35
+ })();
36
+
37
+ const clear = (val: T) => {
38
+ if (noClear) {return;}
39
+ !!handleClear ? handleClear(val) : model.set(null);
40
+ };
41
+
42
+ const tips = computed((): TableOptionSpace.iTableOptionTipMeta | null => {
43
+ const val = model.get();
44
+ if (val == null) {return null;}
45
+ return {
46
+ noClear,
47
+ display: () => display(val),
48
+ onClear: () => {
49
+ clear(val);
50
+ reload();
51
+ },
52
+ onClick: () => {handleClickTip?.(val);},
53
+ };
54
+ });
55
+
56
+ option.hooks.onClearFilter.use(() => {
57
+ const val = model.get();
58
+ if (val == null) {return;}
59
+ clear(val);
60
+ });
61
+
62
+ option.hooks.onTips.use((list) => {!!tips.value && list.unshift(tips.value);});
63
+
64
+ option.hooks.onQueryParam.use(async () => {
65
+ const val = model.get();
66
+ if (val == null) {return;}
67
+ return getQueryParam(val);
68
+ });
69
+
70
+ const reload = () => option.methods.pageMethods.reload();
71
+
72
+ return { model, reload };
73
+ }
@@ -16,6 +16,8 @@ export {useDialog} from "./components/useDialog";
16
16
  export {$dialog} from "./components/$dialog";
17
17
  export {List} from "./components/List";
18
18
  // export {Item} from "./components/Item";
19
+ export {ListPanel} from './components/ListPanel';
20
+ export {ListOption} from './components/ListOption';
19
21
  export {useMessage} from "./components/useMessage";
20
22
  export {$message} from "./components/$message";
21
23
  export {useNotice} from "./components/useNotice";
@@ -131,6 +133,8 @@ export {Paragraph} from './components/Paragraph';
131
133
  export {ParagraphItem} from './components/ParagraphItem';
132
134
  export {ImagePreviewer} from './components/ImagePreviewer/ImagePreviewer';
133
135
  export {Corner} from './components/Corner';
136
+ export {useContextmenuOptions} from './components/useContextmenuOptions';
137
+ export type {iContextmenuOption} from './components/useContextmenuOptions';
134
138
 
135
139
  export {VirtualTable} from './components/VirtualTable';
136
140
  export {Table} from './components/Table';
@@ -284,6 +288,8 @@ export {createWebDraggier} from './components/createWebDraggier';
284
288
  export {createScrollDraggier} from './components/createScrollDraggier';
285
289
  export {loadFile} from './components/loadFile';
286
290
  export {getDeviceInfo, clearDeviceInfo, eDeviceType} from './utils/getDeviceInfo';
291
+ export {useTableFilter} from './components/useTableFilter';
292
+ export {createSimpleDate} from './components/createSimpleDate';
287
293
 
288
294
  // @ts-ignore
289
295
  setComponentPrefix(globalComponentPrefix);