ch3chi-commons-vue 1.2.0 → 1.8.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 (112) hide show
  1. package/package.json +2 -1
  2. package/src/api/ApiService.ts +869 -0
  3. package/src/auth/AuthorizationService.ts +138 -0
  4. package/src/auth/PermissionDescriptor.ts +99 -0
  5. package/src/auth/keys.ts +5 -0
  6. package/src/components/CAlert.vue +188 -0
  7. package/src/components/CAlertDefine.ts +20 -0
  8. package/src/components/CBSToast.vue +119 -0
  9. package/src/components/CGlobalSpinner.vue +84 -0
  10. package/src/components/CImage.vue +67 -0
  11. package/src/components/CRowCheckBox.vue +75 -0
  12. package/src/components/CRowTextInput.vue +27 -0
  13. package/src/components/CTable.vue +524 -0
  14. package/src/components/CTableDefine.ts +566 -0
  15. package/src/components/CTableTD.vue +28 -0
  16. package/src/components/HasPermission.vue +28 -0
  17. package/src/components/form/CChangePasswordFormField.vue +146 -0
  18. package/src/components/form/CCheckBoxFormField.vue +91 -0
  19. package/src/components/form/CCheckBoxPlatFormField.vue +94 -0
  20. package/src/components/form/CDateFormField.vue +149 -0
  21. package/src/components/form/CDateQueryField.vue +111 -0
  22. package/src/components/form/CDateRangeFormField.vue +138 -0
  23. package/src/components/form/CFilePickerFormField.vue +471 -0
  24. package/src/components/form/CRadioFormField.vue +62 -0
  25. package/src/components/form/CRadioPlatFormField.vue +67 -0
  26. package/src/components/form/CSelectFormField.vue +175 -0
  27. package/src/components/form/CTextAreaFormField.vue +84 -0
  28. package/src/components/form/CTextInputFormField.vue +99 -0
  29. package/src/components/form/CTinyMCEEditorFormField.vue +99 -0
  30. package/src/components/form/SCTextInputFormField.vue +129 -0
  31. package/src/composables/useCheckBoxFormField.ts +126 -0
  32. package/src/composables/useRadioFormField.ts +106 -0
  33. package/src/directive/CBootstrapDirective.ts +83 -0
  34. package/src/directive/CDateFormatterDirective.ts +37 -0
  35. package/src/directive/CFTurnstileDirective.ts +46 -0
  36. package/src/directive/CFormDirective.ts +57 -0
  37. package/src/directive/PermissionDirective.ts +102 -0
  38. package/src/env.d.ts +19 -0
  39. package/src/index.ts +83 -0
  40. package/src/model/BSFieldStyleConfig.ts +349 -0
  41. package/src/model/BaseDictionary.ts +86 -0
  42. package/src/model/BaseFormDataModel.ts +623 -0
  43. package/src/model/BaseListViewModel.ts +392 -0
  44. package/src/model/CBSModalViewModel.ts +91 -0
  45. package/src/model/CFileDataModel.ts +181 -0
  46. package/src/model/CImageViewModel.ts +34 -0
  47. package/src/model/CMenuItem.ts +199 -0
  48. package/src/model/EmailReceiverDataModel.ts +149 -0
  49. package/src/model/EmptyDataModel.ts +25 -0
  50. package/src/model/FormOptions.ts +112 -0
  51. package/src/model/LoginDataModel.ts +51 -0
  52. package/src/model/PasswordDataModel.ts +70 -0
  53. package/src/model/QueryParameter.ts +310 -0
  54. package/src/model/SessionUser.ts +110 -0
  55. package/src/model/ShowMessageDataModel.ts +69 -0
  56. package/src/model/TokenUser.ts +157 -0
  57. package/src/stores/FormDataStore.ts +73 -0
  58. package/src/stores/ViewStore.ts +701 -0
  59. package/src/stores/VueSessionStoreInstaller.ts +22 -0
  60. package/src/types/turnstile.d.ts +8 -0
  61. package/src/utils/CToolUtils.ts +133 -0
  62. package/dist/api/ApiService.d.ts +0 -233
  63. package/dist/auth/AuthorizationService.d.ts +0 -56
  64. package/dist/auth/PermissionDescriptor.d.ts +0 -37
  65. package/dist/components/CAlert.vue.d.ts +0 -17
  66. package/dist/components/CAlertDefine.d.ts +0 -14
  67. package/dist/components/CBSToast.vue.d.ts +0 -6
  68. package/dist/components/CGlobalSpinner.vue.d.ts +0 -13
  69. package/dist/components/CRowCheckBox.vue.d.ts +0 -14
  70. package/dist/components/CRowTextInput.vue.d.ts +0 -10
  71. package/dist/components/CTable.vue.d.ts +0 -24
  72. package/dist/components/CTableDefine.d.ts +0 -201
  73. package/dist/components/CTableTD.vue.d.ts +0 -7
  74. package/dist/components/form/CChangePasswordFormField.vue.d.ts +0 -14
  75. package/dist/components/form/CCheckBoxFormField.vue.d.ts +0 -30
  76. package/dist/components/form/CDateFormField.vue.d.ts +0 -17
  77. package/dist/components/form/CDateQueryField.vue.d.ts +0 -16
  78. package/dist/components/form/CDateRangeFormField.vue.d.ts +0 -17
  79. package/dist/components/form/CFilePickerFormField.vue.d.ts +0 -28
  80. package/dist/components/form/CRadioFormField.vue.d.ts +0 -30
  81. package/dist/components/form/CSelectFormField.vue.d.ts +0 -18
  82. package/dist/components/form/CTextAreaFormField.vue.d.ts +0 -16
  83. package/dist/components/form/CTextInputFormField.vue.d.ts +0 -22
  84. package/dist/directive/CBootstrapDirective.d.ts +0 -17
  85. package/dist/directive/CDateFormatterDirective.d.ts +0 -10
  86. package/dist/directive/CFTurnstileDirective.d.ts +0 -15
  87. package/dist/directive/CFormDirective.d.ts +0 -9
  88. package/dist/directive/PermissionDirective.d.ts +0 -15
  89. package/dist/index.cjs.js +0 -19103
  90. package/dist/index.d.ts +0 -45
  91. package/dist/index.es.js +0 -19086
  92. package/dist/model/BSFieldStyleConfig.d.ts +0 -121
  93. package/dist/model/BaseDictionary.d.ts +0 -34
  94. package/dist/model/BaseFormDataModel.d.ts +0 -199
  95. package/dist/model/BaseListViewModel.d.ts +0 -165
  96. package/dist/model/CBSModalViewModel.d.ts +0 -44
  97. package/dist/model/CFileDataModel.d.ts +0 -74
  98. package/dist/model/CImageViewModel.d.ts +0 -8
  99. package/dist/model/CMenuItem.d.ts +0 -86
  100. package/dist/model/EmailReceiverDataModel.d.ts +0 -57
  101. package/dist/model/EmptyDataModel.d.ts +0 -7
  102. package/dist/model/FormOptions.d.ts +0 -60
  103. package/dist/model/LoginDataModel.d.ts +0 -12
  104. package/dist/model/PasswordDataModel.d.ts +0 -15
  105. package/dist/model/QueryParameter.d.ts +0 -92
  106. package/dist/model/SessionUser.d.ts +0 -45
  107. package/dist/model/ShowMessageDataModel.d.ts +0 -44
  108. package/dist/model/TokenUser.d.ts +0 -50
  109. package/dist/stores/FormDataStore.d.ts +0 -31
  110. package/dist/stores/ViewStore.d.ts +0 -349
  111. package/dist/style.css +0 -223
  112. package/dist/utils/CToolUtils.d.ts +0 -53
@@ -0,0 +1,349 @@
1
+ /**
2
+ * BSFieldStyleConfig 配置物件
3
+ * 用於以配置方式自訂欄位外觀和行為
4
+ */
5
+
6
+ export interface IBSFieldStyleConfig {
7
+ // ----- 容器配置 -----
8
+ containerClass?: string;
9
+
10
+ // ----- Label 配置 -----
11
+ labelClass?: string;
12
+ labelPrefix?: string; // label 前置內容
13
+ labelSuffix?: string; // label 後置內容
14
+ hideLabel?: boolean;
15
+
16
+ // ----- required label 配置 -----
17
+ requiredLabelClass?: string;
18
+ requiredLabelText?: string;
19
+
20
+ // plain text 配置
21
+ plainTextClass?: string;
22
+
23
+ // ----- Input 配置 -----
24
+ inputClass?: string;
25
+ inputPrefix?: {
26
+ text?: string;
27
+ class?: string;
28
+ };
29
+ inputSuffix?: {
30
+ text?: string;
31
+ class?: string;
32
+ };
33
+ wrapperClass?: string; // input-group 的 class
34
+
35
+ // ----- Select 配置 -----
36
+ selectClass?: string;
37
+ selectSize?: 'sm' | 'lg'; // Bootstrap select 大小
38
+ selectMultiple?: boolean; // 是否多選
39
+ selectPlaceholder?: string; // placeholder 文字
40
+
41
+ // ----- Textarea 配置 -----
42
+ textareaClass?: string;
43
+ textareaRows?: number; // 預設行數
44
+ textareaResize?: 'none' | 'both' | 'horizontal' | 'vertical'; // 調整大小方式
45
+ textareaAutoGrow?: boolean; // 自動調整高度
46
+
47
+ // ----- Checkbox/Radio 配置 -----
48
+ checkboxClass?: string;
49
+ checkboxLabelClass?: string;
50
+ checkboxWrapperClass?: string; // form-check div 的 class
51
+ checkboxHelperIconClass?: string; // checkbox helper icon class
52
+ radioClass?: string;
53
+ radioLabelClass?: string;
54
+ radioWrapperClass?: string; // form-check div 的 class
55
+ radioInline?: boolean; // 是否水平排列
56
+ radioHelperIconClass?: string; // radio helper icon class
57
+
58
+ // ----- File Input 配置 -----
59
+ fileClass?: string;
60
+ fileAccept?: string; // 允許的檔案類型
61
+ fileMultiple?: boolean; // 是否多檔案選擇
62
+ fileDragDrop?: boolean; // 是否支援拖放
63
+
64
+ // ----- Date Button 配置 -----
65
+ calendarIconClass?: string;
66
+ calendarClearIconClass?: string;
67
+
68
+ // ----- Button 配置 -----
69
+ changePasswordButtonClass?: string;
70
+ changePasswordButtonIcon?: string;
71
+
72
+ // ----- Error 配置 -----
73
+ errorClass?: string;
74
+ errorPrefix?: string;
75
+
76
+ }
77
+
78
+ /**
79
+ * BSFieldStyleConfig 類別
80
+ */
81
+ export class BSFieldStyleConfig {
82
+
83
+ /**
84
+ * 單一實例
85
+ */
86
+ static instance: BSFieldStyleConfig = new BSFieldStyleConfig();
87
+
88
+ /**
89
+ * 合併配置
90
+ * @param config 要合併到全域實例的配置
91
+ */
92
+ static merge(config: IBSFieldStyleConfig) {
93
+ this.instance.config = { ...this.instance.config, ...config };
94
+ }
95
+
96
+ /**
97
+ * 混合多個樣式配置,建立新的 BSFieldStyleConfig 實例
98
+ * 優先順序:propStyle > defaultStyle > instance(全域設定)
99
+ *
100
+ * @param defaultStyle 預設樣式配置(例如組件內建的預設值)
101
+ * @param propStyle 組件 prop 傳入的樣式配置
102
+ * @returns 合併後的 BSFieldStyleConfig 實例
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // 在組件中使用
107
+ * const bStyleConfig = BSFieldStyleConfig.mix(
108
+ * { plainTextClass: 'form-control-plaintext bg-light' }, // 組件預設值
109
+ * props.styleConfig // 從 prop 傳入的值
110
+ * );
111
+ * ```
112
+ */
113
+ static mix(defaultStyle: IBSFieldStyleConfig, propStyle?: IBSFieldStyleConfig): BSFieldStyleConfig {
114
+ // 合併順序:預設樣式 <- 全域設定 <- prop 樣式
115
+ const mergedConfig = {
116
+ ...defaultStyle,
117
+ ...this.instance.config,
118
+ ...(propStyle || {})
119
+ };
120
+ return new BSFieldStyleConfig(mergedConfig);
121
+ }
122
+
123
+ // ~ ----------------------------------------------------------
124
+ // ~ constructor
125
+
126
+ constructor(public config: IBSFieldStyleConfig = {}) {
127
+ }
128
+
129
+ // 取得容器 class
130
+ get containerClass(): string {
131
+ return this.config.containerClass || 'form-group';
132
+ }
133
+
134
+ // 取得 label class
135
+ get labelClass(): string {
136
+ return this.config.labelClass || 'form-label';
137
+ }
138
+
139
+ // 取得 input class
140
+ get inputClass(): string {
141
+ return this.config.inputClass || 'form-control';
142
+ }
143
+
144
+ // 取得 wrapper class(用於 input-group)
145
+ get wrapperClass(): string {
146
+ return this.config.wrapperClass || 'input-group';
147
+ }
148
+
149
+ // 取得 error class
150
+ get errorClass(): string {
151
+ return this.config.errorClass || 'invalid-feedback d-block mt-1';
152
+ }
153
+
154
+ // 是否隱藏 label
155
+ get hideLabel(): boolean {
156
+ return this.config.hideLabel || false;
157
+ }
158
+
159
+ // 取得 required label class 樣式
160
+ get requiredLabelClass(): string {
161
+ return this.config.requiredLabelClass || 'text-danger px-1';
162
+ }
163
+
164
+ // 取得 required label 文字
165
+ get requiredLabelText(): string {
166
+ return this.config.requiredLabelText || '*';
167
+ }
168
+
169
+ // 取得 plain text class
170
+ get plainTextClass(): string {
171
+ return this.config.plainTextClass || 'form-control-plaintext';
172
+ }
173
+
174
+ // 是否有 input prefix
175
+ get hasInputPrefix(): boolean {
176
+ return !!this.config.inputPrefix?.text;
177
+ }
178
+
179
+ // 是否有 input suffix
180
+ get hasInputSuffix(): boolean {
181
+ return !!this.config.inputSuffix?.text;
182
+ }
183
+
184
+ // 取得 input prefix text
185
+ get inputPrefixText(): string {
186
+ return this.config.inputPrefix?.text || '';
187
+ }
188
+
189
+ // 取得 input suffix text
190
+ get inputSuffixText(): string {
191
+ return this.config.inputSuffix?.text || '';
192
+ }
193
+
194
+ // 取得 input prefix class
195
+ get inputPrefixClass(): string {
196
+ return this.config.inputPrefix?.class || 'input-group-text';
197
+ }
198
+
199
+ // 取得 input suffix class
200
+ get inputSuffixClass(): string {
201
+ return this.config.inputSuffix?.class || 'input-group-text';
202
+ }
203
+
204
+ // ----- Select 相關屬性 -----
205
+
206
+ // 取得 select class
207
+ get selectClass(): string {
208
+ let baseClass = this.config.selectClass || 'form-select';
209
+ if (this.config.selectSize) {
210
+ baseClass += ` form-select-${this.config.selectSize}`;
211
+ }
212
+ return baseClass;
213
+ }
214
+
215
+ // 是否多選 select
216
+ get selectMultiple(): boolean {
217
+ return this.config.selectMultiple || false;
218
+ }
219
+
220
+ // 取得 select placeholder
221
+ get selectPlaceholder(): string {
222
+ return this.config.selectPlaceholder || '';
223
+ }
224
+
225
+ // ----- Textarea 相關屬性 -----
226
+
227
+ // 取得 textarea class
228
+ get textareaClass(): string {
229
+ return this.config.textareaClass || 'form-control';
230
+ }
231
+
232
+ // 取得 textarea rows
233
+ get textareaRows(): number {
234
+ return this.config.textareaRows || 3;
235
+ }
236
+
237
+ // 取得 textarea resize 樣式
238
+ get textareaResizeStyle(): string {
239
+ return this.config.textareaResize ? `resize: ${this.config.textareaResize}` : '';
240
+ }
241
+
242
+ // 是否自動調整高度
243
+ get textareaAutoGrow(): boolean {
244
+ return this.config.textareaAutoGrow || false;
245
+ }
246
+
247
+ // ----- Checkbox 相關屬性 -----
248
+
249
+ // 取得 checkbox class
250
+ get checkboxClass(): string {
251
+ return this.config.checkboxClass || 'form-check-input';
252
+ }
253
+
254
+ // 取得 checkbox label class
255
+ get checkboxLabelClass(): string {
256
+ return this.config.checkboxLabelClass || 'form-check-label';
257
+ }
258
+
259
+ // 取得 checkbox wrapper class
260
+ get checkboxWrapperClass(): string {
261
+ return this.config.checkboxWrapperClass || 'form-check';
262
+ }
263
+
264
+ get checkboxHelperIconClass(): string {
265
+ return this.config.checkboxHelperIconClass || '';
266
+ }
267
+
268
+ // ----- Radio 相關屬性 -----
269
+
270
+ // 取得 radio class
271
+ get radioClass(): string {
272
+ return this.config.radioClass || 'form-check-input';
273
+ }
274
+
275
+ // 取得 radio label class
276
+ get radioLabelClass(): string {
277
+ return this.config.radioLabelClass || 'form-check-label';
278
+ }
279
+
280
+ // 取得 radio wrapper class
281
+ get radioWrapperClass(): string {
282
+ let baseClass = this.config.radioWrapperClass || 'form-check';
283
+ if (this.config.radioInline) {
284
+ baseClass += ' form-check-inline';
285
+ }
286
+ return baseClass;
287
+ }
288
+
289
+ // 是否 radio inline 排列
290
+ get radioInline(): boolean {
291
+ return this.config.radioInline || false;
292
+ }
293
+
294
+ // 取得 radio helper icon class
295
+ get radioHelperIconClass(): string {
296
+ return this.config.radioHelperIconClass || '';
297
+ }
298
+
299
+ // ----- File Input 相關屬性 -----
300
+
301
+ // 取得 file input class
302
+ get fileClass(): string {
303
+ return this.config.fileClass || 'form-control';
304
+ }
305
+
306
+ // 取得 file accept 屬性
307
+ get fileAccept(): string {
308
+ return this.config.fileAccept || '';
309
+ }
310
+
311
+ // 是否多檔案選擇
312
+ get fileMultiple(): boolean {
313
+ return this.config.fileMultiple || false;
314
+ }
315
+
316
+ // 是否支援拖放
317
+ get fileDragDrop(): boolean {
318
+ return this.config.fileDragDrop || false;
319
+ }
320
+
321
+ // ----- Date Button 相關屬性 -----
322
+
323
+ // 取得 calendar icon class
324
+ get calendarIconClass(): string {
325
+ return this.config.calendarIconClass || 'bi bi-calendar-event';
326
+ }
327
+
328
+ // 取得 calendar clear icon class
329
+ get calendarClearIconClass(): string {
330
+ return this.config.calendarClearIconClass || 'bi bi-x-circle' ;
331
+ }
332
+
333
+ // ----- button -----
334
+ // 取得 change password button class
335
+ get changePasswordButtonClass(): string {
336
+ return this.config.changePasswordButtonClass || 'btn btn-warning';
337
+ }
338
+
339
+ // 取得 change password button icon
340
+ get changePasswordButtonIcon(): string {
341
+ return this.config.changePasswordButtonIcon || '';
342
+ }
343
+ }
344
+
345
+ // ~ ----------------------------------------------------------
346
+
347
+ // 防止 Vite/rollup tree-shake 掉 type export
348
+ export const __BSFieldStyleConfigDefine__ = null as unknown as
349
+ IBSFieldStyleConfig;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * BaseDictionary class
3
+ * 用於 distionary store 的基底類別
4
+ */
5
+ export abstract class BaseDictionary {
6
+ protected data: Record<string, any> = {};
7
+ dataProvider: (key: string) => Promise<any> | any = () => ({});
8
+ lastUpdatedAt: number = Date.now();
9
+
10
+ protected constructor(data: Partial<BaseDictionary> = {}) {
11
+ if (data) {
12
+ Object.assign(this, data);
13
+ }
14
+ this.init();
15
+ }
16
+
17
+ /**
18
+ * 初始化方法,讓子類別可以覆寫以進行自訂初始化
19
+ * @protected
20
+ */
21
+ abstract init():void;
22
+
23
+ val(key: string): any {
24
+ return this.data[key];
25
+ }
26
+
27
+ setVal(key: string, value: any): void {
28
+ this.data[key] = value;
29
+ }
30
+
31
+ hasVal(key: string): boolean {
32
+ return key in this.data;
33
+ }
34
+
35
+ /**
36
+ * 載入所有字典資料
37
+ * 使用 Promise.allSettled 確保即使某個載入失敗,其他的也能繼續執行
38
+ */
39
+ async loadAll(): Promise<void> {
40
+ const keys = Object.keys(this.data);
41
+ const results = await Promise.allSettled(keys.map(key => this.loadDictionary(key)));
42
+ // 可選:記錄失敗的項目
43
+ results.forEach((result, index) => {
44
+ if (result.status === 'rejected') {
45
+ console.error(`Failed to load dictionary for key "${keys[index]}":`, result.reason);
46
+ }
47
+ });
48
+ }
49
+
50
+ /**
51
+ * load dictionary data
52
+ * 支援 Promise 或是直接回傳資料物件
53
+ * @param key
54
+ */
55
+ async loadDictionary(key: string): Promise<Record<string, any>> {
56
+ const result = this.dataProvider(key);
57
+ if (result instanceof Promise) {
58
+ return result.then(data => {
59
+ this.data[key] = data;
60
+ this.lastUpdatedAt = Date.now();
61
+ return data;
62
+ });
63
+ }
64
+ this.data[key] = result;
65
+ this.lastUpdatedAt = Date.now();
66
+ return Promise.resolve(result);
67
+ }
68
+
69
+ loadFromStore(storeData: Record<string, any>): this {
70
+ this.data = storeData.data || {};
71
+ return this;
72
+ }
73
+
74
+ // ~ ----------------------------------------------------------
75
+ }
76
+
77
+ export class CBaseDictionary extends BaseDictionary {
78
+
79
+ constructor(data: Partial<CBaseDictionary> = {}) {
80
+ super(data);
81
+ }
82
+
83
+ init(): void {
84
+ // 子類別可覆寫此方法進行初始化
85
+ }
86
+ }