@g1cloud/bluesea 5.0.0-alpha.1

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 (69) hide show
  1. package/LICENSE +6 -0
  2. package/css/bluesea-base.scss +6 -0
  3. package/css/component.scss +164 -0
  4. package/css/font.scss +3 -0
  5. package/css/frame/default.scss +149 -0
  6. package/css/layout.scss +116 -0
  7. package/css/reset.scss +58 -0
  8. package/css/utility.scss +228 -0
  9. package/css/variable.scss +34 -0
  10. package/dist/bluesea.js +2465 -0
  11. package/dist/bluesea.umd.cjs +2466 -0
  12. package/dist/component/BSButton.vue.d.ts +15 -0
  13. package/dist/component/basic/BSPopup.vue.d.ts +9 -0
  14. package/dist/component/grid/BSDateRangeFilter.vue.d.ts +56 -0
  15. package/dist/component/grid/BSDateRangeFilters.vue.d.ts +23 -0
  16. package/dist/component/grid/BSGrid.vue.d.ts +80 -0
  17. package/dist/component/grid/BSGridCell.vue.d.ts +47 -0
  18. package/dist/component/grid/BSGridCheckboxCell.vue.d.ts +19 -0
  19. package/dist/component/grid/BSGridCheckboxHeaderCell.vue.d.ts +19 -0
  20. package/dist/component/grid/BSGridControl.vue.d.ts +53 -0
  21. package/dist/component/grid/BSGridHeaderCell.vue.d.ts +20 -0
  22. package/dist/component/grid/BSGridLookup.vue.d.ts +21 -0
  23. package/dist/component/grid/BSGridPageNavigation.vue.d.ts +51 -0
  24. package/dist/component/grid/BSTextFilter.vue.d.ts +41 -0
  25. package/dist/component/grid/DateFilterModel.d.ts +4 -0
  26. package/dist/component/grid/GridLib.d.ts +3 -0
  27. package/dist/component/grid/GridModel.d.ts +35 -0
  28. package/dist/component/input/BSCheckbox.vue.d.ts +50 -0
  29. package/dist/component/input/BSCheckboxGroup.vue.d.ts +43 -0
  30. package/dist/component/input/BSDateInput.vue.d.ts +56 -0
  31. package/dist/component/input/BSMultiSelect.vue.d.ts +43 -0
  32. package/dist/component/input/BSNumberInput.vue.d.ts +49 -0
  33. package/dist/component/input/BSRadioButton.vue.d.ts +61 -0
  34. package/dist/component/input/BSRadioButtonGroup.vue.d.ts +43 -0
  35. package/dist/component/input/BSSelect.vue.d.ts +43 -0
  36. package/dist/component/input/BSSelectModel.d.ts +0 -0
  37. package/dist/component/input/BSSelectPopup.vue.d.ts +55 -0
  38. package/dist/component/input/BSTextArea.vue.d.ts +49 -0
  39. package/dist/component/input/BSTextInput.vue.d.ts +49 -0
  40. package/dist/component/input/BSTreeSelect.vue.d.ts +43 -0
  41. package/dist/component/input/InternalDateInput.vue.d.ts +36 -0
  42. package/dist/component/layout/BSTabSheet.vue.d.ts +37 -0
  43. package/dist/component/layout/TabSheetModel.d.ts +5 -0
  44. package/dist/component/tree/BSTree.vue.d.ts +63 -0
  45. package/dist/component/tree/BSTreeRow.vue.d.ts +54 -0
  46. package/dist/component/tree/TreeLib.d.ts +5 -0
  47. package/dist/component/tree/TreeModel.d.ts +2 -0
  48. package/dist/directive/vClickOutside.d.ts +11 -0
  49. package/dist/frame/FrameModel.d.ts +23 -0
  50. package/dist/frame/default/DefaultBody.vue.d.ts +2 -0
  51. package/dist/frame/default/DefaultFrameModel.d.ts +35 -0
  52. package/dist/frame/default/DefaultHeader.vue.d.ts +2 -0
  53. package/dist/frame/default/HeaderLogo.vue.d.ts +2 -0
  54. package/dist/frame/default/HeaderTab.vue.d.ts +16 -0
  55. package/dist/frame/default/HeaderTabs.vue.d.ts +2 -0
  56. package/dist/frame/default/SidebarMenu.vue.d.ts +2 -0
  57. package/dist/frame/default/SidebarMenuItem.vue.d.ts +16 -0
  58. package/dist/frame/default/SidebarMenuLink.vue.d.ts +20 -0
  59. package/dist/index.d.ts +35 -0
  60. package/dist/model/CommonTypes.d.ts +8 -0
  61. package/dist/model/FilterModel.d.ts +69 -0
  62. package/dist/model/SearchModel.d.ts +16 -0
  63. package/dist/style.css +3665 -0
  64. package/dist/util/componentUtil.d.ts +7 -0
  65. package/dist/util/formatUtil.d.ts +61 -0
  66. package/dist/util/routeUtil.d.ts +2 -0
  67. package/dist/util/typeUtil.d.ts +18 -0
  68. package/dist/util/waitUtil.d.ts +19 -0
  69. package/package.json +48 -0
@@ -0,0 +1,2465 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { defineComponent, openBlock, createElementBlock, toDisplayString, ref, normalizeStyle, createElementVNode, withDirectives, mergeProps, toHandlers, vModelText, createCommentVNode, computed, watch, createVNode, useSlots, normalizeClass, renderSlot, Fragment, renderList, createBlock, Transition, withCtx, onMounted, onBeforeUnmount, withModifiers, withKeys, createTextVNode, reactive, nextTick, unref, vShow, inject, resolveComponent, provide, shallowReactive, markRaw, resolveDynamicComponent } from "vue";
8
+ import dayjs from "dayjs";
9
+ import { useRouter, useRoute } from "vue-router";
10
+ const _hoisted_1$w = { class: "bs-button" };
11
+ const _sfc_main$A = /* @__PURE__ */ defineComponent({
12
+ __name: "BSButton",
13
+ props: {
14
+ caption: {}
15
+ },
16
+ setup(__props) {
17
+ return (_ctx, _cache) => {
18
+ return openBlock(), createElementBlock("button", _hoisted_1$w, toDisplayString(_ctx.caption), 1);
19
+ };
20
+ }
21
+ });
22
+ const _hoisted_1$v = { class: "input-area" };
23
+ const _hoisted_2$k = ["id", "autocomplete", "disabled", "maxlength", "name", "placeholder"];
24
+ const _hoisted_3$f = {
25
+ key: 0,
26
+ class: "message"
27
+ };
28
+ const _sfc_main$z = /* @__PURE__ */ defineComponent({
29
+ __name: "BSTextInput",
30
+ props: {
31
+ id: {},
32
+ placeholder: {},
33
+ name: {},
34
+ modelValue: {},
35
+ maxlength: {},
36
+ disabled: { type: Boolean },
37
+ required: { type: Boolean },
38
+ width: { default: "200px" },
39
+ autocomplete: {}
40
+ },
41
+ emits: ["update:modelValue"],
42
+ setup(__props, { emit: __emit }) {
43
+ const props = __props;
44
+ const emit = __emit;
45
+ const value = ref(props.modelValue);
46
+ const handlers = {
47
+ change: () => emit("update:modelValue", String(value.value || ""))
48
+ };
49
+ const messages = ref();
50
+ return (_ctx, _cache) => {
51
+ return openBlock(), createElementBlock("div", {
52
+ style: normalizeStyle({ width: _ctx.width }),
53
+ class: "bs-text-input"
54
+ }, [
55
+ createElementVNode("div", _hoisted_1$v, [
56
+ withDirectives(createElementVNode("input", mergeProps({
57
+ id: _ctx.id,
58
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => value.value = $event),
59
+ autocomplete: _ctx.autocomplete,
60
+ disabled: _ctx.disabled,
61
+ maxlength: _ctx.maxlength,
62
+ name: _ctx.name,
63
+ placeholder: _ctx.placeholder,
64
+ type: "text"
65
+ }, toHandlers(handlers, true)), null, 16, _hoisted_2$k), [
66
+ [vModelText, value.value]
67
+ ])
68
+ ]),
69
+ messages.value ? (openBlock(), createElementBlock("div", _hoisted_3$f)) : createCommentVNode("", true)
70
+ ], 4);
71
+ };
72
+ }
73
+ });
74
+ const _hoisted_1$u = { class: "input-area" };
75
+ const _hoisted_2$j = ["id", "autocomplete", "disabled", "maxlength", "name", "placeholder"];
76
+ const _hoisted_3$e = /* @__PURE__ */ createElementVNode("div", { class: "message-area" }, null, -1);
77
+ const _sfc_main$y = /* @__PURE__ */ defineComponent({
78
+ __name: "BSNumberInput",
79
+ props: {
80
+ id: {},
81
+ placeholder: {},
82
+ name: {},
83
+ modelValue: {},
84
+ maxlength: {},
85
+ disabled: { type: Boolean },
86
+ required: { type: Boolean },
87
+ width: { default: "200px" },
88
+ autocomplete: {}
89
+ },
90
+ emits: ["update:modelValue"],
91
+ setup(__props, { emit: __emit }) {
92
+ const props = __props;
93
+ const emit = __emit;
94
+ const value = ref(props.modelValue);
95
+ const handlers = {
96
+ change: () => emit("update:modelValue", value.value || void 0)
97
+ };
98
+ return (_ctx, _cache) => {
99
+ return openBlock(), createElementBlock("div", {
100
+ style: normalizeStyle({ width: _ctx.width }),
101
+ class: "bs-number-input"
102
+ }, [
103
+ createElementVNode("div", _hoisted_1$u, [
104
+ withDirectives(createElementVNode("input", mergeProps({
105
+ id: _ctx.id,
106
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => value.value = $event),
107
+ autocomplete: _ctx.autocomplete,
108
+ disabled: _ctx.disabled,
109
+ maxlength: _ctx.maxlength,
110
+ name: _ctx.name,
111
+ placeholder: _ctx.placeholder,
112
+ pattern: "\\d*",
113
+ type: "text"
114
+ }, toHandlers(handlers, true)), null, 16, _hoisted_2$j), [
115
+ [vModelText, value.value]
116
+ ])
117
+ ]),
118
+ _hoisted_3$e
119
+ ], 4);
120
+ };
121
+ }
122
+ });
123
+ const _hoisted_1$t = ["id", "disabled", "maxlength", "name", "placeholder", "value"];
124
+ const _sfc_main$x = /* @__PURE__ */ defineComponent({
125
+ __name: "InternalDateInput",
126
+ props: {
127
+ id: {},
128
+ placeholder: {},
129
+ name: {},
130
+ modelValue: {},
131
+ disabled: { type: Boolean },
132
+ required: { type: Boolean },
133
+ resolution: {},
134
+ endTime: { type: Boolean },
135
+ displayFormat: {}
136
+ },
137
+ emits: ["update:modelValue"],
138
+ setup(__props, { emit: __emit }) {
139
+ const props = __props;
140
+ const emit = __emit;
141
+ const VALUE_FORMAT = computed(() => {
142
+ if (props.resolution === "DAY")
143
+ return "YYYYMMDD";
144
+ else if (props.resolution === "HOUR")
145
+ return "YYYYMMDDHH";
146
+ else
147
+ return "YYYYMMDDHHMM";
148
+ });
149
+ const convertStringToDate = (str) => {
150
+ if (str) {
151
+ let value2 = dayjs(str, VALUE_FORMAT.value);
152
+ if (props.endTime) {
153
+ value2 = value2.endOf(props.resolution.toLowerCase());
154
+ }
155
+ return value2;
156
+ }
157
+ };
158
+ const convertDateToString = (date) => {
159
+ return date ? dayjs(date).format(VALUE_FORMAT.value) : "";
160
+ };
161
+ const focused = ref(false);
162
+ const value = ref(convertDateToString(props.modelValue));
163
+ const formattedValue = computed(() => {
164
+ var _a;
165
+ return ((_a = convertStringToDate(value.value)) == null ? void 0 : _a.format(props.displayFormat)) || "";
166
+ });
167
+ const maxlength = computed(() => 12);
168
+ const emitValue = (event) => {
169
+ const inputValue = event.target.value;
170
+ value.value = inputValue;
171
+ const date = convertStringToDate(inputValue);
172
+ emit("update:modelValue", date);
173
+ };
174
+ return (_ctx, _cache) => {
175
+ return openBlock(), createElementBlock("input", {
176
+ id: _ctx.id,
177
+ disabled: _ctx.disabled,
178
+ maxlength: maxlength.value,
179
+ name: _ctx.name,
180
+ placeholder: _ctx.placeholder,
181
+ value: focused.value ? value.value : formattedValue.value,
182
+ type: "text",
183
+ onBlur: _cache[0] || (_cache[0] = ($event) => focused.value = false),
184
+ onChange: emitValue,
185
+ onFocus: _cache[1] || (_cache[1] = ($event) => focused.value = true),
186
+ "on:update:modelValue": _cache[2] || (_cache[2] = () => {
187
+ })
188
+ }, null, 40, _hoisted_1$t);
189
+ };
190
+ }
191
+ });
192
+ const _hoisted_1$s = { class: "bs-date-input" };
193
+ const _hoisted_2$i = { class: "input-area" };
194
+ const _hoisted_3$d = /* @__PURE__ */ createElementVNode("span", { class: "icon" }, "calendar_month", -1);
195
+ const _sfc_main$w = /* @__PURE__ */ defineComponent({
196
+ __name: "BSDateInput",
197
+ props: {
198
+ id: {},
199
+ placeholder: {},
200
+ name: {},
201
+ modelValue: {},
202
+ disabled: { type: Boolean },
203
+ required: { type: Boolean },
204
+ width: { default: "200px" },
205
+ resolution: { default: "MINUTE" },
206
+ displayFormat: { default: "YYYY-MM-DD HH:mm Z" }
207
+ },
208
+ emits: ["update:modelValue"],
209
+ setup(__props, { emit: __emit }) {
210
+ const props = __props;
211
+ const emit = __emit;
212
+ const value = ref();
213
+ const emitValue = (value2) => {
214
+ emit("update:modelValue", value2);
215
+ };
216
+ watch(
217
+ () => props.modelValue,
218
+ () => value.value = props.modelValue ? dayjs(props.modelValue) : void 0,
219
+ { immediate: true }
220
+ );
221
+ return (_ctx, _cache) => {
222
+ return openBlock(), createElementBlock("div", _hoisted_1$s, [
223
+ createElementVNode("div", _hoisted_2$i, [
224
+ _hoisted_3$d,
225
+ createVNode(_sfc_main$x, {
226
+ id: _ctx.id,
227
+ modelValue: value.value,
228
+ "onUpdate:modelValue": [
229
+ _cache[0] || (_cache[0] = ($event) => value.value = $event),
230
+ emitValue
231
+ ],
232
+ disabled: !!_ctx.disabled,
233
+ "display-format": _ctx.displayFormat,
234
+ name: _ctx.name,
235
+ placeholder: _ctx.placeholder,
236
+ required: !!_ctx.required,
237
+ resolution: _ctx.resolution
238
+ }, null, 8, ["id", "modelValue", "disabled", "display-format", "name", "placeholder", "required", "resolution"])
239
+ ])
240
+ ]);
241
+ };
242
+ }
243
+ });
244
+ let nextId = 0;
245
+ const componentUtil = {
246
+ handleExternalErrorMessage(showErrorMessage, errorMessage, elementId) {
247
+ if (elementId) {
248
+ const el = document.getElementById(elementId);
249
+ if (el) {
250
+ if (!showErrorMessage || !errorMessage || errorMessage.length === 0) {
251
+ el.style.display = "none";
252
+ } else {
253
+ el.style.display = "";
254
+ el.innerText = errorMessage || "";
255
+ }
256
+ }
257
+ }
258
+ },
259
+ generateNextId(prefix) {
260
+ return `${prefix}-${++nextId}`;
261
+ },
262
+ isRelativeSize(size) {
263
+ return (size == null ? void 0 : size.endsWith("%")) || false;
264
+ },
265
+ delayed(func, millis = 200) {
266
+ if (millis <= 0) {
267
+ func();
268
+ } else {
269
+ window.setTimeout(func, millis);
270
+ }
271
+ }
272
+ };
273
+ const _hoisted_1$r = ["id", "checked", "disabled", "name"];
274
+ const _hoisted_2$h = ["for"];
275
+ const _hoisted_3$c = ["for"];
276
+ const _sfc_main$v = /* @__PURE__ */ defineComponent({
277
+ __name: "BSCheckbox",
278
+ props: {
279
+ id: { default: () => componentUtil.generateNextId("checkbox") },
280
+ name: {},
281
+ label: {},
282
+ modelValue: { type: Boolean },
283
+ disabled: { type: Boolean }
284
+ },
285
+ emits: ["update:modelValue"],
286
+ setup(__props, { emit: __emit }) {
287
+ const props = __props;
288
+ const emit = __emit;
289
+ const checked = ref(props.modelValue);
290
+ const slots = useSlots();
291
+ const hasLabelSlot = computed(() => !!(slots == null ? void 0 : slots.default));
292
+ const handlers = {
293
+ change: (event) => {
294
+ checked.value = event.target.checked;
295
+ emit("update:modelValue", checked.value);
296
+ }
297
+ };
298
+ watch(
299
+ () => props.modelValue,
300
+ () => checked.value = props.modelValue
301
+ );
302
+ return (_ctx, _cache) => {
303
+ return openBlock(), createElementBlock("span", {
304
+ class: normalizeClass([{ checked: checked.value }, "bs-checkbox"])
305
+ }, [
306
+ createElementVNode("input", mergeProps({
307
+ id: _ctx.id,
308
+ checked: checked.value,
309
+ disabled: _ctx.disabled,
310
+ name: _ctx.name,
311
+ class: "",
312
+ type: "checkbox"
313
+ }, toHandlers(handlers, true)), null, 16, _hoisted_1$r),
314
+ _ctx.label ? (openBlock(), createElementBlock("label", {
315
+ key: 0,
316
+ for: _ctx.id,
317
+ class: "text-label"
318
+ }, toDisplayString(_ctx.label), 9, _hoisted_2$h)) : createCommentVNode("", true),
319
+ hasLabelSlot.value ? (openBlock(), createElementBlock("label", {
320
+ key: 1,
321
+ for: _ctx.id,
322
+ class: "slot-label cursor-pointer"
323
+ }, [
324
+ renderSlot(_ctx.$slots, "default", { disabled: _ctx.disabled })
325
+ ], 8, _hoisted_3$c)) : createCommentVNode("", true)
326
+ ], 2);
327
+ };
328
+ }
329
+ });
330
+ const _hoisted_1$q = { class: "bs-checkbox-group" };
331
+ const _sfc_main$u = /* @__PURE__ */ defineComponent({
332
+ __name: "BSCheckboxGroup",
333
+ props: {
334
+ modelValue: { default: () => [] },
335
+ items: { default: () => [] },
336
+ valueProvider: {},
337
+ labelProvider: {}
338
+ },
339
+ emits: ["update:modelValue"],
340
+ setup(__props, { emit: __emit }) {
341
+ const props = __props;
342
+ const emit = __emit;
343
+ const itemLabel = (item) => {
344
+ return props.labelProvider ? props.labelProvider(item) : String(item);
345
+ };
346
+ const itemValue = (item) => {
347
+ return props.valueProvider ? props.valueProvider(item) : item;
348
+ };
349
+ const containsItem = (item) => {
350
+ const value = itemValue(item);
351
+ return props.modelValue.includes(value);
352
+ };
353
+ const toggleItemValue = (checked, item) => {
354
+ const value = itemValue(item);
355
+ const contains = props.modelValue.includes(value);
356
+ if (checked && !contains) {
357
+ const newValue = [...props.modelValue, value];
358
+ emit("update:modelValue", newValue);
359
+ } else if (!checked && contains) {
360
+ const index = props.modelValue.indexOf(value);
361
+ const newValue = props.modelValue.toSpliced(index, 1);
362
+ emit("update:modelValue", newValue);
363
+ }
364
+ };
365
+ return (_ctx, _cache) => {
366
+ return openBlock(), createElementBlock("div", _hoisted_1$q, [
367
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (item) => {
368
+ return openBlock(), createBlock(_sfc_main$v, {
369
+ key: String(item),
370
+ label: itemLabel(item),
371
+ "model-value": containsItem(item),
372
+ "onUpdate:modelValue": ($event) => toggleItemValue($event, item)
373
+ }, null, 8, ["label", "model-value", "onUpdate:modelValue"]);
374
+ }), 128))
375
+ ]);
376
+ };
377
+ }
378
+ });
379
+ const _hoisted_1$p = ["id", "checked", "disabled", "name"];
380
+ const _hoisted_2$g = ["for"];
381
+ const _hoisted_3$b = ["for"];
382
+ const _sfc_main$t = /* @__PURE__ */ defineComponent({
383
+ __name: "BSRadioButton",
384
+ props: {
385
+ id: { default: () => componentUtil.generateNextId("radio") },
386
+ name: {},
387
+ label: {},
388
+ modelValue: {},
389
+ itemValue: {},
390
+ disabled: { type: Boolean }
391
+ },
392
+ emits: ["update:modelValue"],
393
+ setup(__props, { emit: __emit }) {
394
+ const props = __props;
395
+ const emit = __emit;
396
+ const checked = computed(() => props.itemValue && props.itemValue === props.modelValue || false);
397
+ const slots = useSlots();
398
+ const hasLabelSlot = computed(() => !!(slots == null ? void 0 : slots.default));
399
+ const handleClick = (event) => {
400
+ const curChecked = event.target.checked;
401
+ if (curChecked) {
402
+ emit("update:modelValue", props.itemValue);
403
+ }
404
+ };
405
+ const handlers = {
406
+ change: handleClick
407
+ // click: handleClick
408
+ };
409
+ return (_ctx, _cache) => {
410
+ return openBlock(), createElementBlock("span", {
411
+ class: normalizeClass([{ checked: checked.value }, "bs-radio-button"])
412
+ }, [
413
+ createElementVNode("input", mergeProps({
414
+ id: _ctx.id,
415
+ checked: checked.value,
416
+ disabled: _ctx.disabled,
417
+ name: _ctx.name,
418
+ class: "",
419
+ type: "radio"
420
+ }, toHandlers(handlers, true)), null, 16, _hoisted_1$p),
421
+ _ctx.label ? (openBlock(), createElementBlock("label", {
422
+ key: 0,
423
+ for: _ctx.id,
424
+ class: "text-label"
425
+ }, toDisplayString(_ctx.label), 9, _hoisted_2$g)) : createCommentVNode("", true),
426
+ hasLabelSlot.value ? (openBlock(), createElementBlock("label", {
427
+ key: 1,
428
+ for: _ctx.id,
429
+ class: "slot-label cursor-pointer"
430
+ }, [
431
+ renderSlot(_ctx.$slots, "default", { disabled: _ctx.disabled })
432
+ ], 8, _hoisted_3$b)) : createCommentVNode("", true)
433
+ ], 2);
434
+ };
435
+ }
436
+ });
437
+ const _hoisted_1$o = { class: "bs-radio-button-group" };
438
+ const _sfc_main$s = /* @__PURE__ */ defineComponent({
439
+ __name: "BSRadioButtonGroup",
440
+ props: {
441
+ modelValue: {},
442
+ items: { default: () => [] },
443
+ valueProvider: {},
444
+ labelProvider: {}
445
+ },
446
+ emits: ["update:modelValue"],
447
+ setup(__props, { emit: __emit }) {
448
+ const props = __props;
449
+ const emit = __emit;
450
+ const itemLabel = (item) => {
451
+ return props.labelProvider ? props.labelProvider(item) : String(item);
452
+ };
453
+ const itemValue = (item) => {
454
+ return props.valueProvider ? props.valueProvider(item) : item;
455
+ };
456
+ const emitValue = (value) => {
457
+ emit("update:modelValue", value);
458
+ };
459
+ return (_ctx, _cache) => {
460
+ return openBlock(), createElementBlock("div", _hoisted_1$o, [
461
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (item) => {
462
+ return openBlock(), createBlock(_sfc_main$t, {
463
+ key: String(itemValue(item)),
464
+ "item-value": itemValue(item),
465
+ label: itemLabel(item),
466
+ "model-value": _ctx.modelValue,
467
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emitValue($event))
468
+ }, null, 8, ["item-value", "label", "model-value"]);
469
+ }), 128))
470
+ ]);
471
+ };
472
+ }
473
+ });
474
+ const _export_sfc = (sfc, props) => {
475
+ const target = sfc.__vccOpts || sfc;
476
+ for (const [key, val] of props) {
477
+ target[key] = val;
478
+ }
479
+ return target;
480
+ };
481
+ const _sfc_main$r = {};
482
+ const _hoisted_1$n = { class: "bs-popup" };
483
+ function _sfc_render(_ctx, _cache) {
484
+ return openBlock(), createBlock(Transition, null, {
485
+ default: withCtx(() => [
486
+ createElementVNode("div", _hoisted_1$n, [
487
+ renderSlot(_ctx.$slots, "default")
488
+ ])
489
+ ]),
490
+ _: 3
491
+ });
492
+ }
493
+ const BSPopup = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["render", _sfc_render]]);
494
+ const _hoisted_1$m = ["onMouseover", "onClick"];
495
+ const _hoisted_2$f = /* @__PURE__ */ createElementVNode("span", { class: "checkbox" }, null, -1);
496
+ const _hoisted_3$a = { class: "label" };
497
+ const _hoisted_4$9 = {
498
+ key: 0,
499
+ class: "sub-items"
500
+ };
501
+ const _sfc_main$q = /* @__PURE__ */ defineComponent({
502
+ __name: "BSSelectPopup",
503
+ props: {
504
+ items: {},
505
+ initialItem: {},
506
+ selectedItems: {},
507
+ itemLabel: { type: Function },
508
+ tree: { type: Boolean }
509
+ },
510
+ emits: ["keyboardHandlerReady", "itemSelected"],
511
+ setup(__props, { emit: __emit }) {
512
+ const props = __props;
513
+ const emit = __emit;
514
+ const nextPopupItem = () => {
515
+ if (props.items.length > 0) {
516
+ if (hoveredPopupItem.value) {
517
+ const index = props.items.indexOf(hoveredPopupItem.value) + 1;
518
+ hoveredPopupItem.value = props.items[index % props.items.length];
519
+ } else {
520
+ hoveredPopupItem.value = props.items[0];
521
+ }
522
+ }
523
+ };
524
+ const prevPopupItem = () => {
525
+ if (props.items.length > 0) {
526
+ if (hoveredPopupItem.value) {
527
+ const index = props.items.indexOf(hoveredPopupItem.value) + props.items.length - 1;
528
+ hoveredPopupItem.value = props.items[index % props.items.length || 0];
529
+ } else {
530
+ hoveredPopupItem.value = props.items[props.items.length - 1];
531
+ }
532
+ }
533
+ };
534
+ const selectItem = () => {
535
+ selectPopupItem(hoveredPopupItem.value);
536
+ };
537
+ const keyboardHandler = (event) => {
538
+ switch (event.key) {
539
+ case "Enter":
540
+ selectItem();
541
+ break;
542
+ case "ArrowDown":
543
+ nextPopupItem();
544
+ break;
545
+ case "ArrowUp":
546
+ prevPopupItem();
547
+ break;
548
+ }
549
+ };
550
+ onMounted(() => emit("keyboardHandlerReady", keyboardHandler));
551
+ onBeforeUnmount(() => emit("keyboardHandlerReady", void 0));
552
+ const hoveredPopupItem = ref();
553
+ hoveredPopupItem.value = props.initialItem;
554
+ const setHoveredPopupItem = (item) => {
555
+ hoveredPopupItem.value = item;
556
+ };
557
+ const selectPopupItem = (item) => {
558
+ emit("itemSelected", item);
559
+ };
560
+ const hasSubItems = (item) => {
561
+ return item && typeof item === "object" && "children" in item && Array.isArray(item.children);
562
+ };
563
+ return (_ctx, _cache) => {
564
+ return openBlock(), createBlock(BSPopup, { class: "bs-select-popup" }, {
565
+ default: withCtx(() => [
566
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (item) => {
567
+ var _a;
568
+ return openBlock(), createElementBlock("div", {
569
+ key: _ctx.itemLabel(item),
570
+ class: normalizeClass([{ hovered: hoveredPopupItem.value === item, "selected-item": (_a = _ctx.selectedItems) == null ? void 0 : _a.includes(item) }, "popup-item"]),
571
+ onMouseover: ($event) => setHoveredPopupItem(item),
572
+ onClick: withModifiers(($event) => selectPopupItem(item), ["stop"])
573
+ }, [
574
+ _hoisted_2$f,
575
+ createElementVNode("span", _hoisted_3$a, toDisplayString(_ctx.itemLabel(item)), 1),
576
+ _ctx.tree && hasSubItems(item) ? (openBlock(), createElementBlock("span", _hoisted_4$9)) : createCommentVNode("", true)
577
+ ], 42, _hoisted_1$m);
578
+ }), 128))
579
+ ]),
580
+ _: 1
581
+ });
582
+ };
583
+ }
584
+ });
585
+ const _hoisted_1$l = ["onKeydown"];
586
+ const _hoisted_2$e = { class: "selected" };
587
+ const _hoisted_3$9 = ["textContent"];
588
+ const _hoisted_4$8 = /* @__PURE__ */ createElementVNode("span", { class: "dropdown-btn" }, "expand_more", -1);
589
+ const _hoisted_5$7 = {
590
+ key: 1,
591
+ class: "message"
592
+ };
593
+ const _sfc_main$p = /* @__PURE__ */ defineComponent({
594
+ __name: "BSSelect",
595
+ props: {
596
+ modelValue: {},
597
+ items: { default: () => [] },
598
+ valueProvider: {},
599
+ labelProvider: {}
600
+ },
601
+ emits: ["update:modelValue"],
602
+ setup(__props, { emit: __emit }) {
603
+ const props = __props;
604
+ const emit = __emit;
605
+ const itemLabel = (item) => {
606
+ return props.labelProvider ? props.labelProvider(item) : String(item);
607
+ };
608
+ const itemValue = (item) => {
609
+ return props.valueProvider ? props.valueProvider(item) : item;
610
+ };
611
+ const findItemFromValue = (value) => {
612
+ return value ? props.items.find((item) => itemValue(item) === value) : void 0;
613
+ };
614
+ const selectedItem = computed(() => findItemFromValue(props.modelValue));
615
+ const selectedItems = computed(() => selectedItem.value ? [selectedItem.value] : []);
616
+ const selectedItemLabel = computed(() => selectedItem.value ? itemLabel(selectedItem.value) : "");
617
+ const showPopup = ref(false);
618
+ const togglePopup = (show) => {
619
+ showPopup.value = show === void 0 ? !showPopup.value : show;
620
+ };
621
+ let keyboardHandler = void 0;
622
+ const setKeyboardHandler = (handler) => {
623
+ keyboardHandler = handler;
624
+ };
625
+ const handleKeyboardEvent = (event) => {
626
+ if (!showPopup.value)
627
+ togglePopup(true);
628
+ if (keyboardHandler)
629
+ keyboardHandler(event);
630
+ };
631
+ const itemSelected = (item) => {
632
+ const value = item ? itemValue(item) : void 0;
633
+ emit("update:modelValue", value);
634
+ showPopup.value = false;
635
+ };
636
+ const messages = ref();
637
+ return (_ctx, _cache) => {
638
+ return openBlock(), createElementBlock("div", {
639
+ class: normalizeClass([{ "popup-open": showPopup.value }, "bs-select"]),
640
+ tabindex: "0",
641
+ onBlur: _cache[0] || (_cache[0] = ($event) => togglePopup(false)),
642
+ onClick: _cache[1] || (_cache[1] = ($event) => togglePopup()),
643
+ onKeydown: [
644
+ _cache[2] || (_cache[2] = withKeys(withModifiers(($event) => togglePopup(), ["stop", "prevent"]), ["space"])),
645
+ withKeys(withModifiers(handleKeyboardEvent, ["stop", "prevent"]), ["enter", "down", "up"]),
646
+ _cache[3] || (_cache[3] = withKeys(withModifiers(($event) => togglePopup(false), ["stop", "prevent"]), ["esc"]))
647
+ ]
648
+ }, [
649
+ createElementVNode("div", _hoisted_2$e, [
650
+ createElementVNode("span", {
651
+ class: "label",
652
+ textContent: toDisplayString(selectedItemLabel.value)
653
+ }, null, 8, _hoisted_3$9),
654
+ _hoisted_4$8
655
+ ]),
656
+ showPopup.value ? (openBlock(), createBlock(_sfc_main$q, {
657
+ key: 0,
658
+ "initial-item": selectedItem.value,
659
+ "item-label": itemLabel,
660
+ items: _ctx.items,
661
+ "selected-items": selectedItems.value,
662
+ onKeyboardHandlerReady: setKeyboardHandler,
663
+ onItemSelected: itemSelected
664
+ }, null, 8, ["initial-item", "items", "selected-items"])) : createCommentVNode("", true),
665
+ messages.value ? (openBlock(), createElementBlock("div", _hoisted_5$7)) : createCommentVNode("", true)
666
+ ], 42, _hoisted_1$l);
667
+ };
668
+ }
669
+ });
670
+ function notNull(value) {
671
+ return value !== null && value !== void 0;
672
+ }
673
+ const _hoisted_1$k = ["onKeydown"];
674
+ const _hoisted_2$d = { class: "selected" };
675
+ const _hoisted_3$8 = ["textContent"];
676
+ const _hoisted_4$7 = /* @__PURE__ */ createElementVNode("span", { class: "dropdown-btn" }, "expand_more", -1);
677
+ const _hoisted_5$6 = {
678
+ key: 1,
679
+ class: "message"
680
+ };
681
+ const _sfc_main$o = /* @__PURE__ */ defineComponent({
682
+ __name: "BSMultiSelect",
683
+ props: {
684
+ modelValue: { default: () => [] },
685
+ items: { default: () => [] },
686
+ valueProvider: {},
687
+ labelProvider: {}
688
+ },
689
+ emits: ["update:modelValue"],
690
+ setup(__props, { emit: __emit }) {
691
+ const props = __props;
692
+ const emit = __emit;
693
+ const itemLabel = (item) => {
694
+ return props.labelProvider ? props.labelProvider(item) : String(item);
695
+ };
696
+ const itemValue = (item) => {
697
+ return props.valueProvider ? props.valueProvider(item) : item;
698
+ };
699
+ const findItemFromValue = (value) => {
700
+ return value ? props.items.find((item) => itemValue(item) === value) : void 0;
701
+ };
702
+ const selectedItems = computed(() => props.modelValue.map(findItemFromValue).filter(notNull));
703
+ const selectedItemsLabel = computed(() => selectedItems.value.map(itemLabel).filter(notNull).join(", "));
704
+ const showPopup = ref(false);
705
+ const togglePopup = (show) => {
706
+ showPopup.value = show === void 0 ? !showPopup.value : show;
707
+ };
708
+ let keyboardHandler = void 0;
709
+ const setKeyboardHandler = (handler) => {
710
+ keyboardHandler = handler;
711
+ };
712
+ const handleKeyboardEvent = (event) => {
713
+ if (!showPopup.value)
714
+ togglePopup(true);
715
+ if (keyboardHandler)
716
+ keyboardHandler(event);
717
+ };
718
+ const itemSelected = (item) => {
719
+ if (item) {
720
+ let newItems = [...selectedItems.value];
721
+ const index = newItems.indexOf(item);
722
+ if (index >= 0) {
723
+ newItems.splice(index, 1);
724
+ } else {
725
+ newItems = props.items.filter((it) => newItems.includes(it) || it === item);
726
+ }
727
+ const values = newItems.map(itemValue);
728
+ emit("update:modelValue", values);
729
+ }
730
+ };
731
+ const messages = ref();
732
+ return (_ctx, _cache) => {
733
+ return openBlock(), createElementBlock("div", {
734
+ class: normalizeClass([{ "popup-open": showPopup.value }, "bs-select"]),
735
+ tabindex: "0",
736
+ onBlur: _cache[0] || (_cache[0] = ($event) => togglePopup(false)),
737
+ onClick: _cache[1] || (_cache[1] = ($event) => togglePopup()),
738
+ onKeydown: [
739
+ _cache[2] || (_cache[2] = withKeys(withModifiers(($event) => togglePopup(), ["stop", "prevent"]), ["space"])),
740
+ withKeys(withModifiers(handleKeyboardEvent, ["stop", "prevent"]), ["enter", "down", "up"]),
741
+ _cache[3] || (_cache[3] = withKeys(withModifiers(($event) => togglePopup(false), ["stop", "prevent"]), ["esc"]))
742
+ ]
743
+ }, [
744
+ createElementVNode("div", _hoisted_2$d, [
745
+ createElementVNode("span", {
746
+ class: "label",
747
+ textContent: toDisplayString(selectedItemsLabel.value)
748
+ }, null, 8, _hoisted_3$8),
749
+ _hoisted_4$7
750
+ ]),
751
+ showPopup.value ? (openBlock(), createBlock(_sfc_main$q, {
752
+ key: 0,
753
+ "item-label": itemLabel,
754
+ items: _ctx.items,
755
+ "selected-items": selectedItems.value,
756
+ onKeyboardHandlerReady: setKeyboardHandler,
757
+ onItemSelected: itemSelected
758
+ }, null, 8, ["items", "selected-items"])) : createCommentVNode("", true),
759
+ messages.value ? (openBlock(), createElementBlock("div", _hoisted_5$6)) : createCommentVNode("", true)
760
+ ], 42, _hoisted_1$k);
761
+ };
762
+ }
763
+ });
764
+ const _hoisted_1$j = ["onKeydown"];
765
+ const _hoisted_2$c = { class: "selected" };
766
+ const _hoisted_3$7 = ["textContent"];
767
+ const _hoisted_4$6 = /* @__PURE__ */ createElementVNode("span", { class: "dropdown-btn" }, "expand_more", -1);
768
+ const _hoisted_5$5 = {
769
+ key: 1,
770
+ class: "message"
771
+ };
772
+ const _sfc_main$n = /* @__PURE__ */ defineComponent({
773
+ __name: "BSTreeSelect",
774
+ props: {
775
+ modelValue: {},
776
+ items: { default: () => [] },
777
+ valueProvider: {},
778
+ labelProvider: {}
779
+ },
780
+ emits: ["update:modelValue"],
781
+ setup(__props, { emit: __emit }) {
782
+ const props = __props;
783
+ const emit = __emit;
784
+ const itemLabel = (item) => {
785
+ return props.labelProvider ? props.labelProvider(item) : String(item);
786
+ };
787
+ const itemValue = (item) => {
788
+ return props.valueProvider ? props.valueProvider(item) : item;
789
+ };
790
+ const findItemFromValue = (value) => {
791
+ return value ? props.items.find((item) => itemValue(item) === value) : void 0;
792
+ };
793
+ const selectedItem = computed(() => findItemFromValue(props.modelValue));
794
+ const selectedItemLabel = computed(() => selectedItem.value ? itemLabel(selectedItem.value) : "");
795
+ const showPopup = ref(false);
796
+ const togglePopup = (show) => {
797
+ showPopup.value = show === void 0 ? !showPopup.value : show;
798
+ };
799
+ let keyboardHandler = void 0;
800
+ const setKeyboardHandler = (handler) => {
801
+ keyboardHandler = handler;
802
+ };
803
+ const handleKeyboardEvent = (event) => {
804
+ if (!showPopup.value)
805
+ togglePopup(true);
806
+ if (keyboardHandler)
807
+ keyboardHandler(event);
808
+ };
809
+ const itemSelected = (item) => {
810
+ const value = item ? itemValue(item) : void 0;
811
+ emit("update:modelValue", value);
812
+ showPopup.value = false;
813
+ };
814
+ const messages = ref();
815
+ return (_ctx, _cache) => {
816
+ return openBlock(), createElementBlock("div", {
817
+ class: normalizeClass([{ "popup-open": showPopup.value }, "bs-tree-select"]),
818
+ tabindex: "0",
819
+ onBlur: _cache[0] || (_cache[0] = ($event) => togglePopup(false)),
820
+ onClick: _cache[1] || (_cache[1] = ($event) => togglePopup()),
821
+ onKeydown: [
822
+ _cache[2] || (_cache[2] = withKeys(withModifiers(($event) => togglePopup(), ["stop", "prevent"]), ["space"])),
823
+ withKeys(withModifiers(handleKeyboardEvent, ["stop", "prevent"]), ["enter", "down", "up"]),
824
+ _cache[3] || (_cache[3] = withKeys(withModifiers(($event) => togglePopup(false), ["stop", "prevent"]), ["esc"]))
825
+ ]
826
+ }, [
827
+ createElementVNode("div", _hoisted_2$c, [
828
+ createElementVNode("span", {
829
+ class: "label",
830
+ textContent: toDisplayString(selectedItemLabel.value)
831
+ }, null, 8, _hoisted_3$7),
832
+ _hoisted_4$6
833
+ ]),
834
+ showPopup.value ? (openBlock(), createBlock(_sfc_main$q, {
835
+ key: 0,
836
+ "initial-item": selectedItem.value,
837
+ "item-label": itemLabel,
838
+ items: _ctx.items,
839
+ tree: "",
840
+ onKeyboardHandlerReady: setKeyboardHandler,
841
+ onItemSelected: itemSelected
842
+ }, null, 8, ["initial-item", "items"])) : createCommentVNode("", true),
843
+ messages.value ? (openBlock(), createElementBlock("div", _hoisted_5$5)) : createCommentVNode("", true)
844
+ ], 42, _hoisted_1$j);
845
+ };
846
+ }
847
+ });
848
+ const _hoisted_1$i = { class: "input-area" };
849
+ const _sfc_main$m = /* @__PURE__ */ defineComponent({
850
+ __name: "BSTextArea",
851
+ props: {
852
+ id: {},
853
+ placeholder: {},
854
+ name: {},
855
+ modelValue: {},
856
+ disabled: { type: Boolean },
857
+ required: { type: Boolean },
858
+ width: { default: "400px" },
859
+ height: {},
860
+ autocomplete: {}
861
+ },
862
+ emits: ["update:modelValue"],
863
+ setup(__props, { emit: __emit }) {
864
+ const props = __props;
865
+ const emit = __emit;
866
+ const value = ref(props.modelValue);
867
+ const emitValue = () => {
868
+ emit("update:modelValue", value.value || "");
869
+ };
870
+ const outerWidth = computed(() => componentUtil.isRelativeSize(props.width) ? props.width : void 0);
871
+ const outerHeight = computed(() => componentUtil.isRelativeSize(props.height) ? props.height : void 0);
872
+ const innerWidth = computed(() => componentUtil.isRelativeSize(props.width) ? "100%" : props.width);
873
+ const innerHeight = computed(() => componentUtil.isRelativeSize(props.height) ? "100%" : props.height);
874
+ return (_ctx, _cache) => {
875
+ return openBlock(), createElementBlock("div", {
876
+ style: normalizeStyle({ width: outerWidth.value, height: outerHeight.value }),
877
+ class: "bs-text-area"
878
+ }, [
879
+ createElementVNode("div", _hoisted_1$i, [
880
+ withDirectives(createElementVNode("textarea", {
881
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => value.value = $event),
882
+ style: normalizeStyle({ width: innerWidth.value, height: innerHeight.value }),
883
+ onChange: emitValue
884
+ }, null, 36), [
885
+ [vModelText, value.value]
886
+ ])
887
+ ])
888
+ ], 4);
889
+ };
890
+ }
891
+ });
892
+ const DEFAULT_GRID_COLUMN_WIDTH = 100;
893
+ const setFixedCellLeftStyle = (table) => {
894
+ if (table) {
895
+ const header = table.querySelector("tr.header-row");
896
+ if (header) {
897
+ const widths = [];
898
+ const headerCells = header.querySelectorAll("th.fixed");
899
+ headerCells.forEach((th) => widths.push(th.getBoundingClientRect().width));
900
+ let acc = 0;
901
+ for (let idx = 0; idx < widths.length; ++idx) {
902
+ widths[idx] = acc += widths[idx];
903
+ }
904
+ widths.unshift(0);
905
+ headerCells.forEach((th, idx) => th.style.left = `${widths[idx]}px`);
906
+ table.querySelectorAll("tr.data-row").forEach((tr) => {
907
+ tr.querySelectorAll("td.fixed").forEach((td, idx) => td.style.left = `${widths[idx]}px`);
908
+ });
909
+ }
910
+ }
911
+ };
912
+ const styleCssToObject = (style) => {
913
+ const result = {};
914
+ style == null ? void 0 : style.split(";").forEach((item) => {
915
+ const [key, value] = item.split(":");
916
+ if (key && value)
917
+ result[key.trim()] = value.trim();
918
+ });
919
+ return result;
920
+ };
921
+ const styleClassToObject = (style) => {
922
+ const result = {};
923
+ style == null ? void 0 : style.split(/\s/).filter((item) => item).forEach((item) => {
924
+ result[item] = true;
925
+ });
926
+ return result;
927
+ };
928
+ const _sfc_main$l = /* @__PURE__ */ defineComponent({
929
+ __name: "BSGridHeaderCell",
930
+ props: {
931
+ column: {},
932
+ columns: {},
933
+ fixed: { type: Boolean }
934
+ },
935
+ setup(__props) {
936
+ const props = __props;
937
+ const thStyleCss = computed(() => {
938
+ return {
939
+ minWidth: `${props.column.width || DEFAULT_GRID_COLUMN_WIDTH}px`,
940
+ maxWidth: `${props.column.width || DEFAULT_GRID_COLUMN_WIDTH}px`
941
+ // left 는 BSGrid 의 onMounted 에서 설정함
942
+ };
943
+ });
944
+ const styleCss = computed(() => {
945
+ return styleCssToObject(props.column.headerCellStyleCss);
946
+ });
947
+ const styleClass = computed(() => {
948
+ return styleClassToObject(props.column.headerCellStyleClass);
949
+ });
950
+ return (_ctx, _cache) => {
951
+ return openBlock(), createElementBlock("th", {
952
+ class: normalizeClass({ fixed: _ctx.fixed }),
953
+ style: normalizeStyle(thStyleCss.value)
954
+ }, [
955
+ createElementVNode("div", {
956
+ class: normalizeClass(styleClass.value),
957
+ style: normalizeStyle(styleCss.value)
958
+ }, toDisplayString(_ctx.column.caption), 7)
959
+ ], 6);
960
+ };
961
+ }
962
+ });
963
+ const DATE_PATTERN = /* @__PURE__ */ new Map([
964
+ ["DATE", "YYYY-MM-DD"],
965
+ ["MINUTE", "YYYY-MM-DD HH:mm"],
966
+ ["SECOND", "YYYY-MM-DD HH:mm:ss"]
967
+ ]);
968
+ const round = (num, decimalPlace = 2) => {
969
+ const pow = Math.pow(10, decimalPlace);
970
+ return Math.round(num * pow) / pow;
971
+ };
972
+ const formatUtil = {
973
+ /**
974
+ * 개행 문자('\r', '\n')를 '<br/>' 태그로 변경한다.
975
+ * @param str 변경할 String
976
+ * @return 개행문자가 '<br/>'로 변경된 String
977
+ */
978
+ escapeNewLine(str) {
979
+ return str ? str.replace(/\r\n|\r|\n/g, "<br />") : "";
980
+ },
981
+ /**
982
+ * `str` 안의 `&<>"'` 문자를 escape 처리한다.
983
+ * @param str 변경할 String
984
+ */
985
+ escapeHtml(str) {
986
+ return str ? str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;") : "";
987
+ },
988
+ /**
989
+ * String 을 개행 문자('\r', '\n') 기준으로 나눈다.
990
+ * @param str
991
+ * @return 개행문자로 나누어진 string 의 array
992
+ */
993
+ splitNewLine(str) {
994
+ return str ? str.split(/\r\n|\r|\n/g) : [];
995
+ },
996
+ /**
997
+ * 날짜를 주어진 형식의 문자열로 변환한다.
998
+ * ````javascript
999
+ * formatUtil.formatDate('2020-10-04T12:34:56.000') // returns "2020.10.04"
1000
+ * formatUtil.formatDate('2020-10-04T12:34:56.000', 'MINUTE') // returns "2020.10.04 12:34"
1001
+ * formatUtil.formatDate(null, 'DATE') // returns ''
1002
+ * formatUtil.formatDate(undefined, 'DATE') // returns ''
1003
+ * ````
1004
+ * @param date 날짜. string, Date, Dayjs 타입 중 하나.
1005
+ * @param pattern 'DATE', 'MINUTE', 또는 날짜 패턴 (ex: 'YYYY.MM.DD')
1006
+ * @returns pattern 형식으로 변환된 문자열. date 나 pattern 이 false 이면 빈 문자열을 리턴한다.
1007
+ */
1008
+ formatDate(date, pattern = "SECOND") {
1009
+ if (!date || !pattern) {
1010
+ return "";
1011
+ }
1012
+ if (typeof date === "string") {
1013
+ date = dayjs(date);
1014
+ }
1015
+ const actualPattern = DATE_PATTERN.get(pattern) || pattern;
1016
+ return dayjs(date).format(actualPattern);
1017
+ },
1018
+ /**
1019
+ * 숫자에 구분점을 넣는다.
1020
+ * @param value
1021
+ * @return
1022
+ */
1023
+ formatNumber(value) {
1024
+ if (value || typeof value === "number") {
1025
+ const regexp = /\B(?=(\d{3})+(?!\d))/g;
1026
+ return String(value).replace(regexp, ",");
1027
+ }
1028
+ return null;
1029
+ },
1030
+ /**
1031
+ * rate 를 받아 percent 를 출력한다.
1032
+ * * 0.1 -> 10%
1033
+ * * 0.55 -> 55%
1034
+ * * 0.551 -> 55.1%
1035
+ * @param value 비율 값
1036
+ * @param withUnit true 이면 % 를 붙이고, false 이면 붙이지 않는다.
1037
+ * @param decimalPlace 소숫점 n번째에서 반올림한다.
1038
+ */
1039
+ formatPercent(value, withUnit = true, decimalPlace = 2) {
1040
+ return value !== void 0 && value !== null && !isNaN(Number(value)) ? `${round(Number(value) * 100, decimalPlace)}${withUnit ? "%" : ""}` : null;
1041
+ },
1042
+ /**
1043
+ * 신용카드번호를 4자리 단위로 나누어 구분자를 넣는다.
1044
+ * @param value
1045
+ * @param separator 구분자
1046
+ */
1047
+ formatCreditCardNo(value, separator = "-") {
1048
+ var _a;
1049
+ return (_a = value.match(/.{1,4}/g)) == null ? void 0 : _a.join(separator);
1050
+ },
1051
+ /**
1052
+ * `HTML`태그가 포함된 문자열에서 text만 남긴다.
1053
+ * @param textIncludedHTMLElement HTML 태그를 포함하는 문자열
1054
+ * @return HTML 태그가 제거된 문자열
1055
+ */
1056
+ toPlainText(textIncludedHTMLElement) {
1057
+ const tmp = document.createElement("DIV");
1058
+ tmp.innerHTML = textIncludedHTMLElement || "";
1059
+ return tmp.textContent || tmp.innerText;
1060
+ }
1061
+ };
1062
+ const _sfc_main$k = /* @__PURE__ */ defineComponent({
1063
+ __name: "BSGridCell",
1064
+ props: {
1065
+ column: {},
1066
+ columns: {},
1067
+ fixed: { type: Boolean },
1068
+ row: {}
1069
+ },
1070
+ setup(__props) {
1071
+ const props = __props;
1072
+ const tdStyleCss = computed(() => {
1073
+ return {
1074
+ minWidth: `${props.column.width || DEFAULT_GRID_COLUMN_WIDTH}px`,
1075
+ maxWidth: `${props.column.width || DEFAULT_GRID_COLUMN_WIDTH}px`
1076
+ // left 는 BSGrid 의 onMounted 에서 설정함
1077
+ };
1078
+ });
1079
+ const tdStyleClass = computed(() => {
1080
+ return {
1081
+ fixed: props.fixed,
1082
+ "text-right": ["NUMBER", "PERCENTAGE"].includes(props.column.cellType || "")
1083
+ };
1084
+ });
1085
+ const styleCss = computed(() => {
1086
+ return styleCssToObject(props.column.cellStyleCss);
1087
+ });
1088
+ const styleClass = computed(() => {
1089
+ return styleClassToObject(props.column.cellStyleClass);
1090
+ });
1091
+ const cellValue = computed(() => {
1092
+ const properties = props.column.propertyId.split(".");
1093
+ let value = props.row;
1094
+ for (let index = 0; index < properties.length; ++index) {
1095
+ if (!value || typeof value !== "object" || !(properties[index] in value)) {
1096
+ return "";
1097
+ }
1098
+ value = value[properties[index]];
1099
+ }
1100
+ return value;
1101
+ });
1102
+ const formattedCellValue = computed(() => {
1103
+ if (props.column.cellType === "NUMBER") {
1104
+ return formatUtil.formatNumber(Number(cellValue.value));
1105
+ } else if (props.column.cellType === "PERCENTAGE") {
1106
+ return formatUtil.formatPercent(Number(cellValue.value));
1107
+ } else if (props.column.cellType === "DATE") {
1108
+ return formatUtil.formatDate(String(cellValue.value), props.column.dateFormat);
1109
+ } else {
1110
+ return cellValue.value;
1111
+ }
1112
+ });
1113
+ return (_ctx, _cache) => {
1114
+ return openBlock(), createElementBlock("td", {
1115
+ class: normalizeClass(tdStyleClass.value),
1116
+ style: normalizeStyle(tdStyleCss.value)
1117
+ }, [
1118
+ createElementVNode("div", {
1119
+ class: normalizeClass(styleClass.value),
1120
+ style: normalizeStyle(styleCss.value)
1121
+ }, [
1122
+ renderSlot(_ctx.$slots, _ctx.column.propertyId, {
1123
+ cell: cellValue.value,
1124
+ row: _ctx.row
1125
+ }, () => [
1126
+ createTextVNode(toDisplayString(formattedCellValue.value), 1)
1127
+ ])
1128
+ ], 6)
1129
+ ], 6);
1130
+ };
1131
+ }
1132
+ });
1133
+ const _hoisted_1$h = { class: "font-icon" };
1134
+ const _sfc_main$j = /* @__PURE__ */ defineComponent({
1135
+ __name: "BSGridCheckboxCell",
1136
+ props: {
1137
+ checked: { type: Boolean }
1138
+ },
1139
+ emits: ["click"],
1140
+ setup(__props, { emit: __emit }) {
1141
+ const emit = __emit;
1142
+ return (_ctx, _cache) => {
1143
+ return openBlock(), createElementBlock("td", {
1144
+ class: normalizeClass([{ checked: _ctx.checked }, "fixed func-cell checkbox bs-clickable"]),
1145
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("click"))
1146
+ }, [
1147
+ createElementVNode("div", _hoisted_1$h, toDisplayString(_ctx.checked ? "check" : ""), 1)
1148
+ ], 2);
1149
+ };
1150
+ }
1151
+ });
1152
+ const _hoisted_1$g = { class: "font-icon" };
1153
+ const _sfc_main$i = /* @__PURE__ */ defineComponent({
1154
+ __name: "BSGridCheckboxHeaderCell",
1155
+ props: {
1156
+ selectedRowCount: {}
1157
+ },
1158
+ emits: ["click"],
1159
+ setup(__props, { emit: __emit }) {
1160
+ const props = __props;
1161
+ const emit = __emit;
1162
+ const checked = computed(() => props.selectedRowCount > 0);
1163
+ return (_ctx, _cache) => {
1164
+ return openBlock(), createElementBlock("th", {
1165
+ class: normalizeClass([{ checked: checked.value }, "fixed func-cell checkbox bs-clickable"]),
1166
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("click"))
1167
+ }, [
1168
+ createElementVNode("div", _hoisted_1$g, toDisplayString(checked.value ? "check" : "check_box_outline_blank"), 1)
1169
+ ], 2);
1170
+ };
1171
+ }
1172
+ });
1173
+ const _hoisted_1$f = { class: "page-navigation" };
1174
+ const _hoisted_2$b = ["data-page", "onClick"];
1175
+ const _sfc_main$h = /* @__PURE__ */ defineComponent({
1176
+ __name: "BSGridPageNavigation",
1177
+ props: {
1178
+ totalCount: { default: 0 },
1179
+ offset: { default: 0 },
1180
+ limit: { default: 10 },
1181
+ visiblePageCount: { default: 10 },
1182
+ maxPage: {}
1183
+ },
1184
+ emits: ["offsetChanged"],
1185
+ setup(__props, { emit: __emit }) {
1186
+ const props = __props;
1187
+ const emit = __emit;
1188
+ const totalPage = computed(() => {
1189
+ const totalPage2 = Math.floor((props.totalCount - 1) / props.limit) + 1;
1190
+ if (props.totalCount < 1)
1191
+ return 1;
1192
+ if (props.maxPage && totalPage2 > props.maxPage)
1193
+ return props.maxPage;
1194
+ return totalPage2 || 0;
1195
+ });
1196
+ const currentPage = computed(() => {
1197
+ return Math.min(Math.floor(props.offset / props.limit) + 1, totalPage.value);
1198
+ });
1199
+ const currentSetFirstPage = computed(() => {
1200
+ return Math.floor((currentPage.value - 1) / props.visiblePageCount) * props.visiblePageCount + 1;
1201
+ });
1202
+ const currentSetLastPage = computed(() => {
1203
+ return Math.min(currentSetFirstPage.value + props.visiblePageCount - 1, totalPage.value);
1204
+ });
1205
+ const visiblePages = computed(() => {
1206
+ if (props.totalCount <= 0)
1207
+ return [];
1208
+ const first = currentSetFirstPage.value;
1209
+ const last = currentSetLastPage.value;
1210
+ const pages = Array(last - first + 1);
1211
+ for (let i = 0; i < pages.length; i++)
1212
+ pages[i] = i + first;
1213
+ return pages;
1214
+ });
1215
+ const prevArrowPage = computed(() => {
1216
+ return currentSetFirstPage.value - 1;
1217
+ });
1218
+ const nextArrowPage = computed(() => {
1219
+ return currentSetLastPage.value + 1;
1220
+ });
1221
+ const isFirstSet = computed(() => {
1222
+ return currentSetFirstPage.value <= 1;
1223
+ });
1224
+ const isLastSet = computed(() => {
1225
+ return currentSetLastPage.value >= totalPage.value;
1226
+ });
1227
+ const goToPage = (page) => {
1228
+ const normalized = Math.max(1, Math.min(page, totalPage.value));
1229
+ if (currentPage.value !== normalized) {
1230
+ const offset = (normalized - 1) * props.limit;
1231
+ emit(
1232
+ "offsetChanged",
1233
+ offset,
1234
+ { offset: props.offset, limit: props.limit, totalCount: props.totalCount }
1235
+ );
1236
+ }
1237
+ };
1238
+ return (_ctx, _cache) => {
1239
+ return openBlock(), createElementBlock("div", _hoisted_1$f, [
1240
+ createElementVNode("span", {
1241
+ class: normalizeClass([{ "disabled": isFirstSet.value }, "font-icon first"]),
1242
+ onClick: _cache[0] || (_cache[0] = withModifiers(($event) => !isFirstSet.value ? goToPage(1) : void 0, ["prevent"]))
1243
+ }, "first_page", 2),
1244
+ createElementVNode("span", {
1245
+ class: normalizeClass([{ "disabled": isFirstSet.value }, "font-icon prev"]),
1246
+ onClick: _cache[1] || (_cache[1] = withModifiers(($event) => !isFirstSet.value ? goToPage(prevArrowPage.value) : void 0, ["prevent"]))
1247
+ }, "keyboard_arrow_left", 2),
1248
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visiblePages.value, (page) => {
1249
+ return openBlock(), createElementBlock("span", {
1250
+ key: page,
1251
+ class: normalizeClass([{ on: page === currentPage.value }, "page"]),
1252
+ "data-page": page,
1253
+ onClick: withModifiers(($event) => goToPage(page), ["prevent"])
1254
+ }, toDisplayString(page), 11, _hoisted_2$b);
1255
+ }), 128)),
1256
+ createElementVNode("span", {
1257
+ class: normalizeClass([{ "disabled": !isLastSet.value }, "font-icon next"]),
1258
+ onClick: _cache[2] || (_cache[2] = withModifiers(($event) => goToPage(nextArrowPage.value), ["prevent"]))
1259
+ }, "keyboard_arrow_right", 2),
1260
+ createElementVNode("span", {
1261
+ class: normalizeClass([{ "disabled": !isLastSet.value }, "font-icon last"]),
1262
+ onClick: _cache[3] || (_cache[3] = withModifiers(($event) => !isLastSet.value ? goToPage(totalPage.value) : void 0, ["prevent"]))
1263
+ }, "last_page", 2)
1264
+ ]);
1265
+ };
1266
+ }
1267
+ });
1268
+ const _hoisted_1$e = { class: "table-wrap" };
1269
+ const _hoisted_2$a = { class: "header-row" };
1270
+ const _hoisted_3$6 = {
1271
+ key: 1,
1272
+ class: "fixed func-cell serial-no"
1273
+ };
1274
+ const _hoisted_4$5 = /* @__PURE__ */ createElementVNode("div", { class: "font-icon" }, "numbers", -1);
1275
+ const _hoisted_5$4 = [
1276
+ _hoisted_4$5
1277
+ ];
1278
+ const _hoisted_6$1 = {
1279
+ key: 1,
1280
+ class: "fixed func-cell serial-no"
1281
+ };
1282
+ const _sfc_main$g = /* @__PURE__ */ defineComponent({
1283
+ __name: "BSGrid",
1284
+ props: {
1285
+ columns: { default: () => [] },
1286
+ data: {},
1287
+ pageInfo: {},
1288
+ width: { default: "100%" },
1289
+ height: { default: "300px" },
1290
+ fixedColumnCount: { default: 0 },
1291
+ showSerial: { type: Boolean },
1292
+ showCheckbox: { type: Boolean },
1293
+ showPageNavigation: { type: Boolean }
1294
+ },
1295
+ emits: ["selectionChanged", "offsetChanged"],
1296
+ setup(__props, { emit: __emit }) {
1297
+ const props = __props;
1298
+ const emit = __emit;
1299
+ const visibleColumns = computed(() => {
1300
+ return props.columns;
1301
+ });
1302
+ const fixedColumns = computed(() => {
1303
+ return props.fixedColumnCount;
1304
+ });
1305
+ const selectedRows = reactive(/* @__PURE__ */ new Set());
1306
+ const isRowSelected = (row) => selectedRows.has(row);
1307
+ const toggleSelection = (row) => {
1308
+ selectedRows.has(row) ? selectedRows.delete(row) : selectedRows.add(row);
1309
+ emit("selectionChanged", selectedRows);
1310
+ };
1311
+ const toggleAll = () => {
1312
+ selectedRows.size > 0 ? selectedRows.clear() : props.data.forEach((row) => selectedRows.add(row));
1313
+ emit("selectionChanged", selectedRows);
1314
+ };
1315
+ const table = ref();
1316
+ watch(
1317
+ () => props.data,
1318
+ async () => {
1319
+ await nextTick();
1320
+ setFixedCellLeftStyle(table.value);
1321
+ },
1322
+ { immediate: true }
1323
+ );
1324
+ const handleOffsetChange = (offset, currentPageInfo) => {
1325
+ emit("offsetChanged", offset, currentPageInfo);
1326
+ };
1327
+ return (_ctx, _cache) => {
1328
+ var _a, _b, _c;
1329
+ return openBlock(), createElementBlock("div", {
1330
+ style: normalizeStyle({ width: _ctx.width, height: _ctx.height }),
1331
+ class: "bs-grid"
1332
+ }, [
1333
+ createElementVNode("div", _hoisted_1$e, [
1334
+ createElementVNode("table", {
1335
+ ref_key: "table",
1336
+ ref: table
1337
+ }, [
1338
+ createElementVNode("thead", null, [
1339
+ createElementVNode("tr", _hoisted_2$a, [
1340
+ _ctx.showCheckbox ? (openBlock(), createBlock(_sfc_main$i, {
1341
+ key: 0,
1342
+ "selected-row-count": selectedRows.size,
1343
+ onClick: toggleAll
1344
+ }, null, 8, ["selected-row-count"])) : createCommentVNode("", true),
1345
+ _ctx.showSerial ? (openBlock(), createElementBlock("th", _hoisted_3$6, _hoisted_5$4)) : createCommentVNode("", true),
1346
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleColumns.value, (column, index) => {
1347
+ return openBlock(), createBlock(_sfc_main$l, {
1348
+ key: column.propertyId,
1349
+ column,
1350
+ columns: visibleColumns.value,
1351
+ fixed: index < fixedColumns.value
1352
+ }, null, 8, ["column", "columns", "fixed"]);
1353
+ }), 128))
1354
+ ])
1355
+ ]),
1356
+ createElementVNode("tbody", null, [
1357
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.data, (row, index) => {
1358
+ var _a2;
1359
+ return openBlock(), createElementBlock("tr", {
1360
+ key: `${row}_${index}`,
1361
+ class: normalizeClass([{ selected: isRowSelected(row) }, "data-row"])
1362
+ }, [
1363
+ _ctx.showCheckbox ? (openBlock(), createBlock(_sfc_main$j, {
1364
+ key: 0,
1365
+ checked: isRowSelected(row),
1366
+ onClick: ($event) => toggleSelection(row)
1367
+ }, null, 8, ["checked", "onClick"])) : createCommentVNode("", true),
1368
+ _ctx.showSerial ? (openBlock(), createElementBlock("td", _hoisted_6$1, [
1369
+ createElementVNode("div", null, toDisplayString(index + (((_a2 = _ctx.pageInfo) == null ? void 0 : _a2.offset) || 0) + 1), 1)
1370
+ ])) : createCommentVNode("", true),
1371
+ (openBlock(true), createElementBlock(Fragment, null, renderList(visibleColumns.value, (column, index2) => {
1372
+ return openBlock(), createBlock(_sfc_main$k, {
1373
+ key: column.propertyId,
1374
+ column,
1375
+ columns: _ctx.columns,
1376
+ fixed: index2 < fixedColumns.value,
1377
+ row
1378
+ }, {
1379
+ [column.propertyId]: withCtx(({ row: row2, cell }) => [
1380
+ renderSlot(_ctx.$slots, column.propertyId, {
1381
+ cell,
1382
+ row: row2
1383
+ })
1384
+ ]),
1385
+ _: 2
1386
+ }, 1032, ["column", "columns", "fixed", "row"]);
1387
+ }), 128))
1388
+ ], 2);
1389
+ }), 128))
1390
+ ])
1391
+ ], 512)
1392
+ ]),
1393
+ _ctx.showPageNavigation ? (openBlock(), createBlock(_sfc_main$h, {
1394
+ key: 0,
1395
+ limit: ((_a = _ctx.pageInfo) == null ? void 0 : _a.limit) || 10,
1396
+ offset: ((_b = _ctx.pageInfo) == null ? void 0 : _b.offset) || 0,
1397
+ "total-count": ((_c = _ctx.pageInfo) == null ? void 0 : _c.totalCount) || 0,
1398
+ "visible-page-count": 20,
1399
+ onOffsetChanged: handleOffsetChange
1400
+ }, null, 8, ["limit", "offset", "total-count"])) : createCommentVNode("", true)
1401
+ ], 4);
1402
+ };
1403
+ }
1404
+ });
1405
+ const isInsideElement = (el, maybeChild) => {
1406
+ let target = maybeChild;
1407
+ while (target) {
1408
+ if (el === target) {
1409
+ return true;
1410
+ }
1411
+ target = target.parentElement;
1412
+ }
1413
+ return false;
1414
+ };
1415
+ const vClickOutside = {
1416
+ mounted: (el, binding) => {
1417
+ const clickListener = (event) => {
1418
+ let target = event.target;
1419
+ if (!isInsideElement(el, target)) {
1420
+ const handler = binding.value;
1421
+ if (handler && typeof handler === "function")
1422
+ handler();
1423
+ }
1424
+ };
1425
+ el.vClickOutsideListener = clickListener;
1426
+ window.addEventListener("click", clickListener);
1427
+ },
1428
+ unmounted: (el) => {
1429
+ const clickListener = el.vClickOutsideListener;
1430
+ window.removeEventListener("click", clickListener);
1431
+ }
1432
+ };
1433
+ class AbstractFilter {
1434
+ constructor(type) {
1435
+ this.type = type;
1436
+ }
1437
+ }
1438
+ class AndFilter extends AbstractFilter {
1439
+ constructor(filters) {
1440
+ super("AND");
1441
+ __publicField(this, "filters");
1442
+ this.filters = filters;
1443
+ }
1444
+ toString() {
1445
+ return this.filters.map((filter) => `(${filter.toString()})`).join(" AND ");
1446
+ }
1447
+ }
1448
+ class InFilter extends AbstractFilter {
1449
+ constructor(names, values, ignoreCase) {
1450
+ super("IN");
1451
+ this.names = names;
1452
+ this.values = values;
1453
+ this.ignoreCase = ignoreCase;
1454
+ }
1455
+ toString() {
1456
+ const names = this.names.join(",");
1457
+ const values = this.values.join(",");
1458
+ return `${names} IN (${values})`;
1459
+ }
1460
+ }
1461
+ class LikeFilter extends AbstractFilter {
1462
+ constructor(names, value, prefix, suffix, ignoreCase) {
1463
+ super("LIKE");
1464
+ this.names = names;
1465
+ this.value = value;
1466
+ this.prefix = prefix;
1467
+ this.suffix = suffix;
1468
+ this.ignoreCase = ignoreCase;
1469
+ }
1470
+ toString() {
1471
+ const names = this.names.join(",");
1472
+ return `${names} LIKE ${this.value}`;
1473
+ }
1474
+ }
1475
+ class BetweenDateFilter extends AbstractFilter {
1476
+ constructor(names, fromValue, toValue) {
1477
+ super("BT_D");
1478
+ this.names = names;
1479
+ this.fromValue = fromValue;
1480
+ this.toValue = toValue;
1481
+ }
1482
+ toString() {
1483
+ const names = this.names.join(",");
1484
+ const from = this.fromValue ? dayjs(this.fromValue).toISOString() : "undefined";
1485
+ const to = this.toValue ? dayjs(this.toValue).toISOString() : "undefined";
1486
+ return `${names} BETWEEN ${from} AND ${to}`;
1487
+ }
1488
+ }
1489
+ const andFilter = (filters) => {
1490
+ return new AndFilter(filters);
1491
+ };
1492
+ const inFilter = (names, values, ignoreCase) => {
1493
+ return new InFilter(names, values, ignoreCase);
1494
+ };
1495
+ const likeFilter = (names, value, prefix, suffix, ignoreCase) => {
1496
+ return new LikeFilter(names, value, prefix, suffix, ignoreCase);
1497
+ };
1498
+ const betweenDateFilter = (names, fromValue, toValue) => {
1499
+ return new BetweenDateFilter(names, fromValue, toValue);
1500
+ };
1501
+ const _hoisted_1$d = { class: "bs-text-filter" };
1502
+ const _hoisted_2$9 = { class: "input-wrap" };
1503
+ const _hoisted_3$5 = ["onKeyup"];
1504
+ const _hoisted_4$4 = { class: "input-wrap" };
1505
+ const _hoisted_5$3 = /* @__PURE__ */ createElementVNode("textarea", { cols: "3" }, null, -1);
1506
+ const _sfc_main$f = /* @__PURE__ */ defineComponent({
1507
+ __name: "BSTextFilter",
1508
+ props: {
1509
+ textFilterItems: { default: () => [] },
1510
+ modelValue: {},
1511
+ activeFilters: {}
1512
+ },
1513
+ emits: ["update:modelValue", "update:activeFilters"],
1514
+ setup(__props, { emit: __emit }) {
1515
+ const props = __props;
1516
+ const emit = __emit;
1517
+ const showFilterItems = ref(false);
1518
+ const toggleFilterItemPopup = () => showFilterItems.value = !showFilterItems.value;
1519
+ const hideFilterItemPopup = () => showFilterItems.value = false;
1520
+ const activeFilters = ref(props.activeFilters || [...props.textFilterItems]);
1521
+ const changeFilterItem = (value) => {
1522
+ if (value) {
1523
+ const idx = activeFilters.value.indexOf(value);
1524
+ if (idx >= 0)
1525
+ activeFilters.value.splice(idx, 1);
1526
+ else
1527
+ activeFilters.value.push(value);
1528
+ const filter = createFilter(inputText.value);
1529
+ emit("update:activeFilters", activeFilters.value, filter);
1530
+ }
1531
+ };
1532
+ const filterMode = ref("INPUT");
1533
+ const changeFilterMode = (mode) => filterMode.value = mode;
1534
+ const getFilterKeyword = (filter) => {
1535
+ if (filter instanceof LikeFilter) {
1536
+ return filter.value;
1537
+ } else if (filter instanceof InFilter) {
1538
+ return filter.values.join("\n");
1539
+ } else {
1540
+ return "";
1541
+ }
1542
+ };
1543
+ const inputText = ref(getFilterKeyword(props.modelValue));
1544
+ const inputTextChanged = () => {
1545
+ var _a;
1546
+ const filter = createFilter(inputText.value);
1547
+ if (((_a = props.modelValue) == null ? void 0 : _a.toString()) !== (filter == null ? void 0 : filter.toString())) {
1548
+ emit("update:modelValue", filter, activeFilters.value);
1549
+ }
1550
+ };
1551
+ const createFilter = (text) => {
1552
+ const keyword = text == null ? void 0 : text.trim();
1553
+ if (!keyword)
1554
+ return void 0;
1555
+ if (filterMode.value === "INPUT") {
1556
+ const names = activeFilters.value.map((filter) => filter.propertyId);
1557
+ return likeFilter(names, keyword, true, true, true);
1558
+ } else if (filterMode.value === "TEXTAREA") {
1559
+ const names = activeFilters.value.filter((filter) => filter.allowMultiLineFilter).map((filter) => filter.propertyId);
1560
+ const keywords = keyword.split("\n");
1561
+ return inFilter(names, keywords, true);
1562
+ }
1563
+ };
1564
+ return (_ctx, _cache) => {
1565
+ return openBlock(), createElementBlock("div", _hoisted_1$d, [
1566
+ withDirectives((openBlock(), createElementBlock("span", {
1567
+ class: "font-icon mr-8 bs-clickable",
1568
+ onClick: toggleFilterItemPopup
1569
+ }, [
1570
+ createTextVNode("checklist")
1571
+ ])), [
1572
+ [unref(vClickOutside), hideFilterItemPopup]
1573
+ ]),
1574
+ withDirectives(createElementVNode("span", _hoisted_2$9, [
1575
+ withDirectives(createElementVNode("input", {
1576
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => inputText.value = $event),
1577
+ type: "text",
1578
+ onChange: inputTextChanged,
1579
+ onKeyup: withKeys(withModifiers(inputTextChanged, ["prevent", "stop"]), ["enter"])
1580
+ }, null, 40, _hoisted_3$5), [
1581
+ [vModelText, inputText.value]
1582
+ ])
1583
+ ], 512), [
1584
+ [vShow, filterMode.value === "INPUT"]
1585
+ ]),
1586
+ withDirectives(createElementVNode("span", _hoisted_4$4, [
1587
+ _hoisted_5$3,
1588
+ createElementVNode("span", {
1589
+ class: "mr-4 font-icon bs-clickable",
1590
+ onClick: _cache[1] || (_cache[1] = ($event) => changeFilterMode("INPUT"))
1591
+ }, "expand_circle_up")
1592
+ ], 512), [
1593
+ [vShow, filterMode.value === "TEXTAREA"]
1594
+ ]),
1595
+ showFilterItems.value ? (openBlock(), createBlock(_sfc_main$q, {
1596
+ key: 0,
1597
+ "item-label": (item) => item.caption,
1598
+ items: _ctx.textFilterItems,
1599
+ "selected-items": activeFilters.value,
1600
+ onItemSelected: changeFilterItem
1601
+ }, null, 8, ["item-label", "items", "selected-items"])) : createCommentVNode("", true)
1602
+ ]);
1603
+ };
1604
+ }
1605
+ });
1606
+ const _hoisted_1$c = { class: "bs-date-range-filter" };
1607
+ const _hoisted_2$8 = { class: "input-area" };
1608
+ const _hoisted_3$4 = /* @__PURE__ */ createElementVNode("span", { class: "font-icon" }, "calendar_month", -1);
1609
+ const _hoisted_4$3 = /* @__PURE__ */ createElementVNode("span", { class: "px-4" }, "~", -1);
1610
+ const _sfc_main$e = /* @__PURE__ */ defineComponent({
1611
+ __name: "BSDateRangeFilter",
1612
+ props: {
1613
+ fromId: {},
1614
+ toId: {},
1615
+ fromName: {},
1616
+ toName: {},
1617
+ modelValue: {},
1618
+ disabled: { type: Boolean },
1619
+ width: { default: "200px" },
1620
+ resolution: { default: "DAY" },
1621
+ displayFormat: { default: "YYYY-MM-DD HH:mm" }
1622
+ },
1623
+ emits: ["update:modelValue"],
1624
+ setup(__props, { emit: __emit }) {
1625
+ const props = __props;
1626
+ const emit = __emit;
1627
+ const fromValue = ref();
1628
+ const toValue = ref();
1629
+ const toISOString = (value, endTime = false) => {
1630
+ if (value) {
1631
+ const date = dayjs(value);
1632
+ if (endTime) {
1633
+ return date.endOf(props.resolution.toLowerCase()).toISOString();
1634
+ } else {
1635
+ return date.startOf(props.resolution.toLowerCase()).toISOString();
1636
+ }
1637
+ }
1638
+ };
1639
+ const emitValue = () => {
1640
+ const value = {
1641
+ from: toISOString(fromValue.value, false),
1642
+ to: toISOString(toValue.value, true)
1643
+ };
1644
+ emit("update:modelValue", value);
1645
+ };
1646
+ return (_ctx, _cache) => {
1647
+ return openBlock(), createElementBlock("div", _hoisted_1$c, [
1648
+ createElementVNode("div", _hoisted_2$8, [
1649
+ _hoisted_3$4,
1650
+ createVNode(_sfc_main$x, {
1651
+ id: _ctx.fromId,
1652
+ modelValue: fromValue.value,
1653
+ "onUpdate:modelValue": [
1654
+ _cache[0] || (_cache[0] = ($event) => fromValue.value = $event),
1655
+ emitValue
1656
+ ],
1657
+ disabled: !!_ctx.disabled,
1658
+ "display-format": _ctx.displayFormat,
1659
+ name: _ctx.fromName,
1660
+ resolution: _ctx.resolution
1661
+ }, null, 8, ["id", "modelValue", "disabled", "display-format", "name", "resolution"]),
1662
+ _hoisted_4$3,
1663
+ createVNode(_sfc_main$x, {
1664
+ id: _ctx.toId,
1665
+ modelValue: toValue.value,
1666
+ "onUpdate:modelValue": [
1667
+ _cache[1] || (_cache[1] = ($event) => toValue.value = $event),
1668
+ emitValue
1669
+ ],
1670
+ disabled: !!_ctx.disabled,
1671
+ "display-format": _ctx.displayFormat,
1672
+ name: _ctx.toName,
1673
+ resolution: _ctx.resolution,
1674
+ "end-time": ""
1675
+ }, null, 8, ["id", "modelValue", "disabled", "display-format", "name", "resolution"])
1676
+ ])
1677
+ ]);
1678
+ };
1679
+ }
1680
+ });
1681
+ const _hoisted_1$b = {
1682
+ key: 0,
1683
+ class: "date-filters .bs-layout-vertical mr-32"
1684
+ };
1685
+ const _hoisted_2$7 = ["onClick"];
1686
+ const _sfc_main$d = /* @__PURE__ */ defineComponent({
1687
+ __name: "BSDateRangeFilters",
1688
+ props: {
1689
+ dateFilter: {},
1690
+ modelValue: {}
1691
+ },
1692
+ emits: ["update:modelValue"],
1693
+ setup(__props, { emit: __emit }) {
1694
+ const props = __props;
1695
+ const emit = __emit;
1696
+ const dateFilterValues = reactive([]);
1697
+ onMounted(() => {
1698
+ var _a;
1699
+ const items = (_a = props.dateFilter) == null ? void 0 : _a.filterItems;
1700
+ if (items && items.length > 0) {
1701
+ dateFilterValues[0] = {
1702
+ propertyId: items[0].propertyId,
1703
+ value: {}
1704
+ };
1705
+ }
1706
+ });
1707
+ const setDateFilterPropertyId = (index, propertyId) => {
1708
+ const item = dateFilterValues[index];
1709
+ if (propertyId)
1710
+ item.propertyId = propertyId;
1711
+ emitValue();
1712
+ };
1713
+ const setDateFilterValue = (index, value) => {
1714
+ const item = dateFilterValues[index];
1715
+ item.value = value || {};
1716
+ emitValue();
1717
+ };
1718
+ const addDateFilter = () => {
1719
+ var _a;
1720
+ const dateFilterItems = ((_a = props.dateFilter) == null ? void 0 : _a.filterItems) || [];
1721
+ if (dateFilterValues.length < dateFilterItems.length) {
1722
+ const selectedPropertyIds = dateFilterValues.map((value) => value.propertyId);
1723
+ const notSelected = dateFilterItems.filter((item) => !selectedPropertyIds.includes(item.propertyId));
1724
+ if (notSelected.length > 0) {
1725
+ dateFilterValues.push({
1726
+ propertyId: notSelected[0].propertyId,
1727
+ value: {}
1728
+ });
1729
+ }
1730
+ }
1731
+ };
1732
+ const removeDateFilter = (index) => {
1733
+ if (index >= 0 && index < dateFilterValues.length) {
1734
+ dateFilterValues.splice(index, 1);
1735
+ emitValue();
1736
+ }
1737
+ };
1738
+ const emitValue = () => {
1739
+ var _a;
1740
+ const filters = dateFilterValues.filter((item) => item.propertyId && (item.value.from || item.value.to)).map((item) => betweenDateFilter([item.propertyId], item.value.from, item.value.to));
1741
+ const and = filters.length > 0 ? andFilter(filters) : void 0;
1742
+ if (((_a = props.modelValue) == null ? void 0 : _a.toString()) !== (and == null ? void 0 : and.toString())) {
1743
+ emit("update:modelValue", and);
1744
+ }
1745
+ };
1746
+ return (_ctx, _cache) => {
1747
+ return _ctx.dateFilter.filterItems ? (openBlock(), createElementBlock("div", _hoisted_1$b, [
1748
+ (openBlock(true), createElementBlock(Fragment, null, renderList(dateFilterValues, (item, index) => {
1749
+ return openBlock(), createElementBlock("div", {
1750
+ key: index,
1751
+ class: "bs-layout-horizontal mb-4 flex-align-center"
1752
+ }, [
1753
+ index === 0 ? (openBlock(), createElementBlock("span", {
1754
+ key: 0,
1755
+ class: normalizeClass([{ disabled: dateFilterValues.length >= _ctx.dateFilter.filterItems.length }, "font-icon bs-clickable mr-4"]),
1756
+ onClick: addDateFilter
1757
+ }, "add_circle", 2)) : (openBlock(), createElementBlock("span", {
1758
+ key: 1,
1759
+ class: "font-icon bs-clickable mr-4",
1760
+ onClick: ($event) => removeDateFilter(index)
1761
+ }, "do_not_disturb_on", 8, _hoisted_2$7)),
1762
+ createVNode(_sfc_main$p, {
1763
+ items: _ctx.dateFilter.filterItems,
1764
+ "label-provider": (filter) => filter.caption,
1765
+ "model-value": item.propertyId,
1766
+ "value-provider": (filter) => filter.propertyId,
1767
+ class: "mr-4",
1768
+ "onUpdate:modelValue": ($event) => setDateFilterPropertyId(index, $event)
1769
+ }, null, 8, ["items", "label-provider", "model-value", "value-provider", "onUpdate:modelValue"]),
1770
+ createVNode(_sfc_main$e, {
1771
+ "from-id": `${item.propertyId}From`,
1772
+ "model-value": item.value,
1773
+ "to-id": `${item.propertyId}To`,
1774
+ "onUpdate:modelValue": ($event) => setDateFilterValue(index, $event)
1775
+ }, null, 8, ["from-id", "model-value", "to-id", "onUpdate:modelValue"])
1776
+ ]);
1777
+ }), 128))
1778
+ ])) : createCommentVNode("", true);
1779
+ };
1780
+ }
1781
+ });
1782
+ const _hoisted_1$a = { class: "bs-grid-lookup bs-layout-horizontal flex-align-start" };
1783
+ const _sfc_main$c = /* @__PURE__ */ defineComponent({
1784
+ __name: "BSGridLookup",
1785
+ props: {
1786
+ config: {}
1787
+ },
1788
+ emits: ["search"],
1789
+ setup(__props, { emit: __emit }) {
1790
+ const emit = __emit;
1791
+ const textFilterValue = ref();
1792
+ const dateFilterValue = ref();
1793
+ const emitSearch = () => {
1794
+ const filters = [];
1795
+ if (textFilterValue.value)
1796
+ filters.push(textFilterValue.value);
1797
+ if (dateFilterValue.value) {
1798
+ dateFilterValue.value.filters.forEach((filter) => filters.push(filter));
1799
+ }
1800
+ const and = filters.length > 0 ? andFilter(filters) : void 0;
1801
+ emit("search", and);
1802
+ };
1803
+ return (_ctx, _cache) => {
1804
+ var _a, _b;
1805
+ return openBlock(), createElementBlock("div", _hoisted_1$a, [
1806
+ ((_a = _ctx.config) == null ? void 0 : _a.textFilter) ? (openBlock(), createBlock(_sfc_main$f, {
1807
+ key: 0,
1808
+ modelValue: textFilterValue.value,
1809
+ "onUpdate:modelValue": [
1810
+ _cache[0] || (_cache[0] = ($event) => textFilterValue.value = $event),
1811
+ emitSearch
1812
+ ],
1813
+ "text-filter-items": _ctx.config.textFilter.filterItems,
1814
+ class: "mr-32"
1815
+ }, null, 8, ["modelValue", "text-filter-items"])) : createCommentVNode("", true),
1816
+ ((_b = _ctx.config) == null ? void 0 : _b.dateFilter) ? (openBlock(), createBlock(_sfc_main$d, {
1817
+ key: 1,
1818
+ modelValue: dateFilterValue.value,
1819
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => dateFilterValue.value = $event),
1820
+ "date-filter": _ctx.config.dateFilter
1821
+ }, null, 8, ["modelValue", "date-filter"])) : createCommentVNode("", true),
1822
+ createElementVNode("div", null, [
1823
+ createVNode(_sfc_main$A, {
1824
+ caption: "Search",
1825
+ onClick: emitSearch
1826
+ })
1827
+ ])
1828
+ ]);
1829
+ };
1830
+ }
1831
+ });
1832
+ const _hoisted_1$9 = { class: "bs-grid-control" };
1833
+ const _hoisted_2$6 = {
1834
+ key: 0,
1835
+ class: "bs-clickable"
1836
+ };
1837
+ const _hoisted_3$3 = {
1838
+ key: 1,
1839
+ class: "bs-clickable"
1840
+ };
1841
+ const _hoisted_4$2 = {
1842
+ key: 2,
1843
+ class: "bs-clickable"
1844
+ };
1845
+ const _hoisted_5$2 = { "data-id": "totalCount" };
1846
+ const _hoisted_6 = { key: 5 };
1847
+ const _sfc_main$b = /* @__PURE__ */ defineComponent({
1848
+ __name: "BSGridControl",
1849
+ props: {
1850
+ showSetting: { type: Boolean },
1851
+ showClearFilter: { type: Boolean },
1852
+ showFilter: { type: Boolean },
1853
+ showLimit: { type: Boolean },
1854
+ showAdd: { type: Boolean },
1855
+ showRemove: { type: Boolean },
1856
+ limitItems: { default: () => [100, 300, 500] },
1857
+ limit: {},
1858
+ totalCount: {}
1859
+ },
1860
+ emits: ["update:limit", "clickAdd", "clickRemove"],
1861
+ setup(__props, { emit: __emit }) {
1862
+ var _a;
1863
+ const props = __props;
1864
+ const emit = __emit;
1865
+ const limitValue = ref(props.limit || ((_a = props.limitItems) == null ? void 0 : _a[0]) || 100);
1866
+ const changeLimit = (limit) => {
1867
+ emit("update:limit", Math.max(1, limit || 0));
1868
+ };
1869
+ return (_ctx, _cache) => {
1870
+ return openBlock(), createElementBlock("div", _hoisted_1$9, [
1871
+ _ctx.showSetting ? (openBlock(), createElementBlock("div", _hoisted_2$6, " 칼럼설정 ")) : createCommentVNode("", true),
1872
+ _ctx.showClearFilter ? (openBlock(), createElementBlock("div", _hoisted_3$3, " 필터초기화 ")) : createCommentVNode("", true),
1873
+ _ctx.showFilter ? (openBlock(), createElementBlock("div", _hoisted_4$2, " 필터 ")) : createCommentVNode("", true),
1874
+ _ctx.showAdd ? (openBlock(), createElementBlock("div", {
1875
+ key: 3,
1876
+ class: "bs-clickable",
1877
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("clickAdd"))
1878
+ }, " 추가 ")) : createCommentVNode("", true),
1879
+ _ctx.showRemove ? (openBlock(), createElementBlock("div", {
1880
+ key: 4,
1881
+ class: "bs-clickable",
1882
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("clickRemove"))
1883
+ }, " 선택삭제 ")) : createCommentVNode("", true),
1884
+ createElementVNode("div", null, [
1885
+ createTextVNode("전체: "),
1886
+ createElementVNode("span", _hoisted_5$2, toDisplayString(unref(formatUtil).formatNumber(_ctx.totalCount)), 1)
1887
+ ]),
1888
+ _ctx.showLimit ? (openBlock(), createElementBlock("div", _hoisted_6, [
1889
+ createVNode(_sfc_main$p, {
1890
+ modelValue: limitValue.value,
1891
+ "onUpdate:modelValue": [
1892
+ _cache[2] || (_cache[2] = ($event) => limitValue.value = $event),
1893
+ changeLimit
1894
+ ],
1895
+ items: _ctx.limitItems,
1896
+ class: "page-length"
1897
+ }, null, 8, ["modelValue", "items"])
1898
+ ])) : createCommentVNode("", true)
1899
+ ]);
1900
+ };
1901
+ }
1902
+ });
1903
+ const _hoisted_1$8 = { class: "bs-tab-sheet bs-layout-vertical" };
1904
+ const _hoisted_2$5 = { class: "tab-bar bs-layout-horizontal" };
1905
+ const _hoisted_3$2 = { class: "tabs flex-grow-1 flex-shrink-1" };
1906
+ const _hoisted_4$1 = ["onClick"];
1907
+ const _hoisted_5$1 = { class: "buttons text-nowrap" };
1908
+ const _sfc_main$a = /* @__PURE__ */ defineComponent({
1909
+ __name: "BSTabSheet",
1910
+ props: {
1911
+ tabs: { default: () => [] }
1912
+ },
1913
+ setup(__props) {
1914
+ const props = __props;
1915
+ const currentTab = ref();
1916
+ const selectTab = (tab) => currentTab.value = tab;
1917
+ onMounted(() => {
1918
+ selectTab(props.tabs[0]);
1919
+ });
1920
+ return (_ctx, _cache) => {
1921
+ return openBlock(), createElementBlock("div", _hoisted_1$8, [
1922
+ createElementVNode("div", _hoisted_2$5, [
1923
+ createElementVNode("div", _hoisted_3$2, [
1924
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.tabs, (tab) => {
1925
+ var _a;
1926
+ return openBlock(), createElementBlock("div", {
1927
+ key: tab.tabId,
1928
+ class: normalizeClass([{ selected: (tab == null ? void 0 : tab.tabId) === ((_a = currentTab.value) == null ? void 0 : _a.tabId) }, "bs-clickable tab"]),
1929
+ onClick: ($event) => selectTab(tab)
1930
+ }, toDisplayString(tab.caption), 11, _hoisted_4$1);
1931
+ }), 128))
1932
+ ]),
1933
+ createElementVNode("div", _hoisted_5$1, [
1934
+ renderSlot(_ctx.$slots, "buttons")
1935
+ ])
1936
+ ]),
1937
+ currentTab.value ? renderSlot(_ctx.$slots, currentTab.value.tabId, { key: 0 }) : createCommentVNode("", true)
1938
+ ]);
1939
+ };
1940
+ }
1941
+ });
1942
+ const defaultTreeChildrenProvider = (item) => {
1943
+ return item && typeof item === "object" && "children" in item ? item.children : void 0;
1944
+ };
1945
+ class TreeRowStatuses {
1946
+ constructor() {
1947
+ __publicField(this, "expanded", /* @__PURE__ */ new Set());
1948
+ __publicField(this, "selected", /* @__PURE__ */ new Set());
1949
+ }
1950
+ }
1951
+ const defaultCaptionProvider = (item) => (item == null ? void 0 : item.toString()) || "";
1952
+ const _hoisted_1$7 = { class: "bs-tree-row" };
1953
+ const _hoisted_2$4 = { class: "row-caption" };
1954
+ const _hoisted_3$1 = ["onClick"];
1955
+ const _hoisted_4 = ["textContent", "onClick", "onDblclick"];
1956
+ const _hoisted_5 = {
1957
+ key: 0,
1958
+ class: "child-rows"
1959
+ };
1960
+ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
1961
+ __name: "BSTreeRow",
1962
+ props: {
1963
+ row: {},
1964
+ childrenProvider: { type: Function, default: defaultTreeChildrenProvider },
1965
+ captionProvider: { type: Function, default: defaultCaptionProvider }
1966
+ },
1967
+ emits: ["toggleRow", "selectRow"],
1968
+ setup(__props, { emit: __emit }) {
1969
+ const props = __props;
1970
+ const emit = __emit;
1971
+ const caption = computed(() => props.captionProvider(props.row));
1972
+ const children = computed(() => props.childrenProvider(props.row));
1973
+ const treeRowStatuses = inject("TREE_ROW_STATUSES");
1974
+ const isOpen = computed(() => (treeRowStatuses == null ? void 0 : treeRowStatuses.expanded.has(props.row)) || false);
1975
+ const toggleRow = () => emit("toggleRow", props.row, !isOpen.value);
1976
+ const toggleChildRow = (row, expanded) => emit("toggleRow", row, expanded);
1977
+ const isSelected = computed(() => (treeRowStatuses == null ? void 0 : treeRowStatuses.selected.has(props.row)) || false);
1978
+ const selectRow = () => emit("selectRow", props.row, !isSelected.value);
1979
+ const selectChildRow = (row, selected) => emit("selectRow", row, selected);
1980
+ const rowIcon = computed(() => children.value && children.value.length > 0 ? isOpen.value ? "arrow_drop_down" : "arrow_right" : "");
1981
+ return (_ctx, _cache) => {
1982
+ const _component_BSTreeRow = resolveComponent("BSTreeRow", true);
1983
+ return openBlock(), createElementBlock("div", _hoisted_1$7, [
1984
+ createElementVNode("div", _hoisted_2$4, [
1985
+ createElementVNode("span", {
1986
+ class: "bs-clickable font-icon w-16",
1987
+ onClick: withModifiers(toggleRow, ["stop"])
1988
+ }, toDisplayString(rowIcon.value), 9, _hoisted_3$1),
1989
+ createElementVNode("span", {
1990
+ class: normalizeClass([{ selected: isSelected.value }, "caption"]),
1991
+ textContent: toDisplayString(caption.value),
1992
+ onClick: withModifiers(selectRow, ["stop"]),
1993
+ onDblclick: withModifiers(toggleRow, ["stop"])
1994
+ }, null, 42, _hoisted_4)
1995
+ ]),
1996
+ children.value && children.value.length > 0 ? withDirectives((openBlock(), createElementBlock("div", _hoisted_5, [
1997
+ (openBlock(true), createElementBlock(Fragment, null, renderList(children.value, (child) => {
1998
+ return openBlock(), createBlock(_component_BSTreeRow, {
1999
+ key: child == null ? void 0 : child.toString(),
2000
+ "caption-provider": _ctx.captionProvider,
2001
+ "children-provider": _ctx.childrenProvider,
2002
+ row: child,
2003
+ onToggleRow: toggleChildRow,
2004
+ onSelectRow: selectChildRow
2005
+ }, null, 8, ["caption-provider", "children-provider", "row"]);
2006
+ }), 128))
2007
+ ], 512)), [
2008
+ [vShow, isOpen.value]
2009
+ ]) : createCommentVNode("", true)
2010
+ ]);
2011
+ };
2012
+ }
2013
+ });
2014
+ const _hoisted_1$6 = { class: "bs-tree" };
2015
+ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
2016
+ __name: "BSTree",
2017
+ props: {
2018
+ data: {},
2019
+ childrenProvider: { type: Function, default: defaultTreeChildrenProvider },
2020
+ captionProvider: { type: Function, default: defaultCaptionProvider },
2021
+ expandedRows: {},
2022
+ selectedRows: {},
2023
+ multiSelect: { type: Boolean }
2024
+ },
2025
+ emits: ["update:expandedRows", "update:selectedRows"],
2026
+ setup(__props, { emit: __emit }) {
2027
+ const props = __props;
2028
+ const emit = __emit;
2029
+ const treeRowStatuses = reactive(new TreeRowStatuses());
2030
+ provide("TREE_ROW_STATUSES", treeRowStatuses);
2031
+ watch(
2032
+ () => props.expandedRows,
2033
+ () => {
2034
+ if (props.expandedRows && props.expandedRows !== treeRowStatuses.expanded) {
2035
+ treeRowStatuses.expanded = props.expandedRows;
2036
+ }
2037
+ },
2038
+ { immediate: true }
2039
+ );
2040
+ const toggleRow = (row, expanded) => {
2041
+ if (expanded) {
2042
+ treeRowStatuses.expanded.add(row);
2043
+ } else {
2044
+ treeRowStatuses.expanded.delete(row);
2045
+ }
2046
+ emit("update:expandedRows", treeRowStatuses.expanded);
2047
+ };
2048
+ watch(
2049
+ () => props.selectedRows,
2050
+ () => {
2051
+ if (props.selectedRows && props.selectedRows !== treeRowStatuses.selected) {
2052
+ treeRowStatuses.selected = props.selectedRows;
2053
+ }
2054
+ },
2055
+ { immediate: true }
2056
+ );
2057
+ const selectRow = (row, selected) => {
2058
+ const selectedItems = treeRowStatuses.selected;
2059
+ if (props.multiSelect) {
2060
+ if (selected) {
2061
+ selectedItems.add(row);
2062
+ } else {
2063
+ selectedItems.delete(row);
2064
+ }
2065
+ emit("update:selectedRows", selectedItems);
2066
+ } else {
2067
+ if (selectedItems.size !== 1 || !selectedItems.has(row)) {
2068
+ selectedItems.clear();
2069
+ selectedItems.add(row);
2070
+ emit("update:selectedRows", selectedItems);
2071
+ }
2072
+ }
2073
+ };
2074
+ return (_ctx, _cache) => {
2075
+ return openBlock(), createElementBlock("div", _hoisted_1$6, [
2076
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.data, (row) => {
2077
+ return openBlock(), createBlock(_sfc_main$9, {
2078
+ key: row == null ? void 0 : row.toString(),
2079
+ "caption-provider": _ctx.captionProvider,
2080
+ "children-provider": _ctx.childrenProvider,
2081
+ row,
2082
+ onToggleRow: toggleRow,
2083
+ onSelectRow: selectRow
2084
+ }, null, 8, ["caption-provider", "children-provider", "row"]);
2085
+ }), 128))
2086
+ ]);
2087
+ };
2088
+ }
2089
+ });
2090
+ class DefaultFrameContext {
2091
+ constructor(config) {
2092
+ __publicField(this, "pageManager");
2093
+ this.config = config;
2094
+ this.pageManager = new PageManager(config.menus, config.extraPages, config.firstPage);
2095
+ }
2096
+ getMenus() {
2097
+ return this.config.menus;
2098
+ }
2099
+ // 현재 route 에 해당하는 Page 를 오픈한다.
2100
+ openCurrentPage(route) {
2101
+ const pagePath = route.path.substring(this.config.framePrefix.length);
2102
+ this.pageManager.openPage(pagePath);
2103
+ }
2104
+ // pagePath 에 해당하는 화면 URL 로 이동한다.
2105
+ async openPagePath(router, pagePath) {
2106
+ const actualPath = pagePath.replace(/^\/+/, "");
2107
+ await router.push({ path: `${this.config.framePrefix}/${actualPath}` });
2108
+ }
2109
+ }
2110
+ const createDefaultFrameContext = (config) => {
2111
+ const defaultConfig = {
2112
+ framePrefix: "/",
2113
+ logoText: "G1 Commerce",
2114
+ menus: [],
2115
+ extraPages: []
2116
+ };
2117
+ const mergedConfig = Object.assign(defaultConfig, config || {});
2118
+ return new DefaultFrameContext(mergedConfig);
2119
+ };
2120
+ const CONTEXT_NAME = "DEFAULT_FRAME_CONTEXT";
2121
+ const provideDefaultFrameContext = (config) => {
2122
+ const context = createDefaultFrameContext(config);
2123
+ provide(CONTEXT_NAME, context);
2124
+ return context;
2125
+ };
2126
+ const useDefaultFrame = () => {
2127
+ const context = inject(CONTEXT_NAME);
2128
+ if (!context)
2129
+ throw new Error("DefaultFrameContext not found. You should call provideDefaultFrameContext().");
2130
+ else
2131
+ return context;
2132
+ };
2133
+ class PageManager {
2134
+ constructor(menus, extraPages, firstPage) {
2135
+ __publicField(this, "openPages", shallowReactive([]));
2136
+ __publicField(this, "pageMap", /* @__PURE__ */ new Map());
2137
+ this.menus = menus;
2138
+ this.extraPages = extraPages;
2139
+ this.firstPage = firstPage;
2140
+ this.collectPages(this.pageMap, this.menus);
2141
+ this.extraPages.forEach((page) => this.pageMap.set(page.pageId, page));
2142
+ }
2143
+ createPageInstance(pagePath) {
2144
+ var _a;
2145
+ let page;
2146
+ if (pagePath === "/" || pagePath === "") {
2147
+ page = this.firstPage;
2148
+ } else {
2149
+ const pageId = (_a = /^\/([^\/]+)/.exec(pagePath)) == null ? void 0 : _a[1];
2150
+ page = pageId ? this.pageMap.get(pageId) : void 0;
2151
+ }
2152
+ if (page) {
2153
+ return reactive({
2154
+ pageId: page.pageId,
2155
+ path: pagePath,
2156
+ active: false,
2157
+ component: markRaw(page.component),
2158
+ // component 는 reactive 하지 않아야 한다.
2159
+ hideTab: page === this.firstPage
2160
+ });
2161
+ }
2162
+ }
2163
+ openPage(pagePath) {
2164
+ let page = this.openPages.find((instance) => instance.path === pagePath);
2165
+ if (!page) {
2166
+ page = this.createPageInstance(pagePath);
2167
+ if (page) {
2168
+ this.openPages.push(page);
2169
+ }
2170
+ }
2171
+ this.setActivePage(page);
2172
+ }
2173
+ collectPages(pageMap, menus) {
2174
+ menus.forEach((menu) => {
2175
+ var _a;
2176
+ (_a = menu.pages) == null ? void 0 : _a.forEach((page) => pageMap.set(page.pageId, page));
2177
+ if (menu.subMenu)
2178
+ this.collectPages(pageMap, menu.subMenu);
2179
+ });
2180
+ }
2181
+ setActivePage(page) {
2182
+ this.openPages.forEach((p) => p.active = p === page);
2183
+ }
2184
+ }
2185
+ const _sfc_main$7 = /* @__PURE__ */ defineComponent({
2186
+ __name: "SidebarMenuLink",
2187
+ props: {
2188
+ menu: {}
2189
+ },
2190
+ emits: ["click"],
2191
+ setup(__props, { emit: __emit }) {
2192
+ const props = __props;
2193
+ const emit = __emit;
2194
+ const context = useDefaultFrame();
2195
+ const menuLink = computed(() => props.menu.pages && props.menu.pages.length > 0 ? `${context.config.framePrefix}/${props.menu.pages[0].pageId}` : void 0);
2196
+ return (_ctx, _cache) => {
2197
+ const _component_router_link = resolveComponent("router-link");
2198
+ return menuLink.value ? (openBlock(), createBlock(_component_router_link, {
2199
+ key: 0,
2200
+ to: menuLink.value,
2201
+ class: "sidebar-menu-link",
2202
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("click"))
2203
+ }, {
2204
+ default: withCtx(() => [
2205
+ createTextVNode(toDisplayString(_ctx.menu.caption), 1)
2206
+ ]),
2207
+ _: 1
2208
+ }, 8, ["to"])) : (openBlock(), createElementBlock("div", {
2209
+ key: 1,
2210
+ class: "sidebar-menu-link",
2211
+ tabindex: "0",
2212
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("click")),
2213
+ onKeyup: _cache[2] || (_cache[2] = withKeys(withModifiers(($event) => emit("click"), ["prevent"]), ["enter"]))
2214
+ }, toDisplayString(_ctx.menu.caption), 33));
2215
+ };
2216
+ }
2217
+ });
2218
+ const _hoisted_1$5 = { class: "sidebar-menu-item" };
2219
+ const _hoisted_2$3 = {
2220
+ key: 0,
2221
+ class: "sidebar-submenu"
2222
+ };
2223
+ const _sfc_main$6 = /* @__PURE__ */ defineComponent({
2224
+ __name: "SidebarMenuItem",
2225
+ props: {
2226
+ menu: {}
2227
+ },
2228
+ setup(__props) {
2229
+ const props = __props;
2230
+ const hasSubMenus = computed(() => {
2231
+ var _a;
2232
+ return (((_a = props.menu.subMenu) == null ? void 0 : _a.length) || 0) > 0;
2233
+ });
2234
+ const showSubMenu = ref(false);
2235
+ const toggleSubMenu = () => showSubMenu.value = !showSubMenu.value;
2236
+ return (_ctx, _cache) => {
2237
+ return openBlock(), createElementBlock("div", _hoisted_1$5, [
2238
+ createVNode(_sfc_main$7, {
2239
+ menu: _ctx.menu,
2240
+ onClick: toggleSubMenu
2241
+ }, null, 8, ["menu"]),
2242
+ hasSubMenus.value && showSubMenu.value ? (openBlock(), createElementBlock("div", _hoisted_2$3, [
2243
+ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.menu.subMenu, (submenu) => {
2244
+ return openBlock(), createBlock(_sfc_main$7, {
2245
+ key: submenu.menuId,
2246
+ menu: submenu
2247
+ }, null, 8, ["menu"]);
2248
+ }), 128))
2249
+ ])) : createCommentVNode("", true)
2250
+ ]);
2251
+ };
2252
+ }
2253
+ });
2254
+ const _hoisted_1$4 = ["onKeyup"];
2255
+ const _hoisted_2$2 = ["onKeydown", "onClick"];
2256
+ const _hoisted_3 = { class: "menu-container" };
2257
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
2258
+ __name: "SidebarMenu",
2259
+ setup(__props) {
2260
+ const showMenu = ref(false);
2261
+ const toggleMenu = () => {
2262
+ showMenu.value = !showMenu.value;
2263
+ };
2264
+ const hideMenu = () => {
2265
+ showMenu.value = false;
2266
+ };
2267
+ const context = useDefaultFrame();
2268
+ return (_ctx, _cache) => {
2269
+ return withDirectives((openBlock(), createElementBlock("div", {
2270
+ class: "sidebar-menu",
2271
+ onKeyup: withKeys(hideMenu, ["esc"])
2272
+ }, [
2273
+ createElementVNode("div", {
2274
+ class: "menu-btn font-icon",
2275
+ tabindex: "0",
2276
+ onKeydown: withKeys(withModifiers(toggleMenu, ["stop"]), ["enter", "space"]),
2277
+ onClick: withModifiers(toggleMenu, ["stop"])
2278
+ }, toDisplayString(showMenu.value ? "menu_open" : "menu"), 41, _hoisted_2$2),
2279
+ createVNode(Transition, { name: "menu-slide" }, {
2280
+ default: withCtx(() => [
2281
+ withDirectives(createElementVNode("div", _hoisted_3, [
2282
+ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(context).getMenus(), (menu) => {
2283
+ return openBlock(), createBlock(_sfc_main$6, {
2284
+ key: menu.menuId,
2285
+ menu
2286
+ }, null, 8, ["menu"]);
2287
+ }), 128))
2288
+ ], 512), [
2289
+ [vShow, showMenu.value]
2290
+ ])
2291
+ ]),
2292
+ _: 1
2293
+ })
2294
+ ], 40, _hoisted_1$4)), [
2295
+ [unref(vClickOutside), hideMenu]
2296
+ ]);
2297
+ };
2298
+ }
2299
+ });
2300
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
2301
+ __name: "HeaderLogo",
2302
+ setup(__props) {
2303
+ const context = useDefaultFrame();
2304
+ const router = useRouter();
2305
+ const goToFirstPage = () => {
2306
+ context.openPagePath(router, "/");
2307
+ };
2308
+ return (_ctx, _cache) => {
2309
+ return openBlock(), createElementBlock("div", {
2310
+ class: "header-logo",
2311
+ onClick: goToFirstPage
2312
+ }, " G1 Commerce ");
2313
+ };
2314
+ }
2315
+ });
2316
+ const _hoisted_1$3 = { class: "header-title" };
2317
+ const _hoisted_2$1 = ["onClick"];
2318
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
2319
+ __name: "HeaderTab",
2320
+ props: {
2321
+ page: {}
2322
+ },
2323
+ setup(__props) {
2324
+ const props = __props;
2325
+ const context = useDefaultFrame();
2326
+ const router = useRouter();
2327
+ const selectPage = () => {
2328
+ context.openPagePath(router, props.page.path);
2329
+ };
2330
+ const closePage = () => {
2331
+ };
2332
+ return (_ctx, _cache) => {
2333
+ return openBlock(), createElementBlock("div", {
2334
+ class: normalizeClass([{ selected: _ctx.page.active }, "header-tab"]),
2335
+ onClick: selectPage
2336
+ }, [
2337
+ createElementVNode("div", _hoisted_1$3, toDisplayString(_ctx.page.pageId), 1),
2338
+ createElementVNode("div", {
2339
+ class: "font-icon close-btn",
2340
+ onClick: withModifiers(closePage, ["stop"])
2341
+ }, " close ", 8, _hoisted_2$1)
2342
+ ], 2);
2343
+ };
2344
+ }
2345
+ });
2346
+ const _hoisted_1$2 = { class: "header-tabs" };
2347
+ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
2348
+ __name: "HeaderTabs",
2349
+ setup(__props) {
2350
+ const context = useDefaultFrame();
2351
+ const openPages = computed(() => context.pageManager.openPages.filter((page) => !page.hideTab));
2352
+ return (_ctx, _cache) => {
2353
+ return openBlock(), createElementBlock("div", _hoisted_1$2, [
2354
+ (openBlock(true), createElementBlock(Fragment, null, renderList(openPages.value, (page) => {
2355
+ return openBlock(), createBlock(_sfc_main$3, {
2356
+ key: page.path,
2357
+ page
2358
+ }, null, 8, ["page"]);
2359
+ }), 128))
2360
+ ]);
2361
+ };
2362
+ }
2363
+ });
2364
+ const _hoisted_1$1 = { class: "default-header" };
2365
+ const _hoisted_2 = /* @__PURE__ */ createElementVNode("div", null, null, -1);
2366
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
2367
+ __name: "DefaultHeader",
2368
+ setup(__props) {
2369
+ return (_ctx, _cache) => {
2370
+ return openBlock(), createElementBlock("header", _hoisted_1$1, [
2371
+ createVNode(_sfc_main$5),
2372
+ createVNode(_sfc_main$4),
2373
+ createVNode(_sfc_main$2),
2374
+ _hoisted_2
2375
+ ]);
2376
+ };
2377
+ }
2378
+ });
2379
+ const _hoisted_1 = { class: "default-body" };
2380
+ const _sfc_main = /* @__PURE__ */ defineComponent({
2381
+ __name: "DefaultBody",
2382
+ setup(__props) {
2383
+ const context = useDefaultFrame();
2384
+ const route = useRoute();
2385
+ const openPages = computed(() => context.pageManager.openPages);
2386
+ watch(() => route.path, () => {
2387
+ context.openCurrentPage(route);
2388
+ }, { immediate: true });
2389
+ return (_ctx, _cache) => {
2390
+ return openBlock(), createElementBlock("div", _hoisted_1, [
2391
+ (openBlock(true), createElementBlock(Fragment, null, renderList(openPages.value, (item) => {
2392
+ return withDirectives((openBlock(), createElementBlock("div", {
2393
+ key: item.path,
2394
+ class: "body-tab"
2395
+ }, [
2396
+ (openBlock(), createBlock(resolveDynamicComponent(item.component)))
2397
+ ])), [
2398
+ [vShow, item.active]
2399
+ ]);
2400
+ }), 128))
2401
+ ]);
2402
+ };
2403
+ }
2404
+ });
2405
+ const waitUntil = async (condition, intervalMilliseconds = 200, maxTrial = 15) => {
2406
+ return await new Promise((resolve) => {
2407
+ let tried = 0;
2408
+ const interval = setInterval(() => {
2409
+ if (tried > maxTrial || condition()) {
2410
+ clearInterval(interval);
2411
+ resolve(void 0);
2412
+ }
2413
+ tried++;
2414
+ }, intervalMilliseconds);
2415
+ });
2416
+ };
2417
+ const waitDuring = async (milliSec = 2e3) => {
2418
+ return new Promise((resolve) => setTimeout(resolve, milliSec));
2419
+ };
2420
+ const tryUntil = (until, tryCall, intervalMilliseconds = 200, maxTrial = 15) => {
2421
+ let tried = 0;
2422
+ const interval = setInterval(() => {
2423
+ tried > maxTrial || until() ? clearInterval(interval) : tryCall == null ? void 0 : tryCall();
2424
+ tried++;
2425
+ }, intervalMilliseconds);
2426
+ };
2427
+ const parsePathParam = (route) => {
2428
+ const pagePath = String(route.params.pagePath);
2429
+ return pagePath.split("/").slice(1);
2430
+ };
2431
+ const BLUESEA_VERSION = "5.0.0";
2432
+ export {
2433
+ BLUESEA_VERSION,
2434
+ _sfc_main$A as BSButton,
2435
+ _sfc_main$v as BSCheckbox,
2436
+ _sfc_main$u as BSCheckboxGroup,
2437
+ _sfc_main$w as BSDateInput,
2438
+ _sfc_main$e as BSDateRangeFilter,
2439
+ _sfc_main$g as BSGrid,
2440
+ _sfc_main$b as BSGridControl,
2441
+ _sfc_main$c as BSGridLookup,
2442
+ _sfc_main$o as BSMultiSelect,
2443
+ _sfc_main$y as BSNumberInput,
2444
+ _sfc_main$t as BSRadioButton,
2445
+ _sfc_main$s as BSRadioButtonGroup,
2446
+ _sfc_main$p as BSSelect,
2447
+ _sfc_main$a as BSTabSheet,
2448
+ _sfc_main$m as BSTextArea,
2449
+ _sfc_main$f as BSTextFilter,
2450
+ _sfc_main$z as BSTextInput,
2451
+ _sfc_main$8 as BSTree,
2452
+ _sfc_main$n as BSTreeSelect,
2453
+ _sfc_main as DefaultBody,
2454
+ DefaultFrameContext,
2455
+ _sfc_main$1 as DefaultHeader,
2456
+ createDefaultFrameContext,
2457
+ formatUtil,
2458
+ notNull,
2459
+ parsePathParam,
2460
+ provideDefaultFrameContext,
2461
+ tryUntil,
2462
+ useDefaultFrame,
2463
+ waitDuring,
2464
+ waitUntil
2465
+ };