@didaoktv/didaoui-uniapp 1.0.0 → 1.2.0

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 (114) hide show
  1. package/README.md +16 -7
  2. package/components/dd-action-sheet/dd-action-sheet.vue +3 -3
  3. package/components/dd-album/album.js +19 -0
  4. package/components/dd-album/dd-album.vue +345 -0
  5. package/components/dd-album/props.js +89 -0
  6. package/components/dd-avatar/avatar.js +19 -0
  7. package/components/dd-avatar/dd-avatar.vue +172 -160
  8. package/components/dd-avatar/props.js +84 -0
  9. package/components/dd-avatar-group/avatarGroup.js +14 -0
  10. package/components/dd-avatar-group/dd-avatar-group.vue +110 -0
  11. package/components/dd-avatar-group/props.js +57 -0
  12. package/components/dd-badge/dd-badge.vue +2 -2
  13. package/components/dd-barcode/dd-barcode.vue +1030 -0
  14. package/components/dd-bill-detail/dd-bill-detail.vue +265 -0
  15. package/components/dd-button/dd-button.vue +17 -17
  16. package/components/dd-calendar/dd-calendar.vue +357 -0
  17. package/components/dd-canvas/dd-canvas.vue +1088 -0
  18. package/components/dd-capsule-button/dd-capsule-button.vue +6 -6
  19. package/components/dd-car-keyboard/carKeyboard.js +6 -0
  20. package/components/dd-car-keyboard/dd-car-keyboard.vue +315 -0
  21. package/components/dd-car-keyboard/props.js +19 -0
  22. package/components/dd-cascader/dd-cascader.vue +405 -0
  23. package/components/dd-cell/dd-cell.vue +50 -23
  24. package/components/dd-cell-group/dd-cell-group.vue +32 -25
  25. package/components/dd-champion-card/dd-champion-card.vue +4 -4
  26. package/components/dd-checkbox/dd-checkbox.vue +30 -39
  27. package/components/dd-checkbox-group/dd-checkbox-group.vue +67 -0
  28. package/components/dd-copy/dd-copy.vue +74 -0
  29. package/components/dd-coupon/dd-coupon.vue +368 -0
  30. package/components/dd-cropper/dd-cropper.vue +1297 -0
  31. package/components/dd-dialog/dd-dialog.vue +1 -1
  32. package/components/dd-divider/dd-divider.vue +3 -3
  33. package/components/dd-dropdown-item/dd-dropdown-item.vue +5 -5
  34. package/components/dd-empty-state/dd-empty-state.vue +1 -1
  35. package/components/dd-field/dd-field.vue +531 -106
  36. package/components/dd-form/dd-form.vue +116 -0
  37. package/components/dd-form/rules.ts +84 -0
  38. package/components/dd-goods-sku/dd-goods-sku.vue +434 -0
  39. package/components/dd-icon/dd-icon.vue +2 -2
  40. package/components/dd-image/dd-image.vue +4 -4
  41. package/components/dd-input/dd-input.vue +5 -5
  42. package/components/dd-keyboard/dd-keyboard.vue +178 -0
  43. package/components/dd-keyboard/keyboard.js +22 -0
  44. package/components/dd-keyboard/props.js +89 -0
  45. package/components/dd-link/dd-link.vue +87 -0
  46. package/components/dd-link/link.js +18 -0
  47. package/components/dd-link/props.js +44 -0
  48. package/components/dd-list-cell/dd-list-cell.vue +4 -4
  49. package/components/dd-loading/dd-loading.vue +1 -1
  50. package/components/dd-loadmore/dd-loadmore.vue +2 -2
  51. package/components/dd-markdown/dd-markdown.vue +344 -0
  52. package/components/dd-markdown/marked.esm.mjs +7 -0
  53. package/components/dd-mini-program-navbar/dd-mini-program-navbar.vue +9 -9
  54. package/components/dd-navigation/dd-navigation.vue +5 -5
  55. package/components/dd-number-keyboard/dd-number-keyboard.vue +200 -0
  56. package/components/dd-number-keyboard/numberKeyboard.js +8 -0
  57. package/components/dd-number-keyboard/props.js +24 -0
  58. package/components/dd-parse/dd-parse.vue +534 -0
  59. package/components/dd-parse/node/handler.wxs +26 -0
  60. package/components/dd-parse/node/node.vue +603 -0
  61. package/components/dd-parse/parse.js +13 -0
  62. package/components/dd-parse/parser.js +1400 -0
  63. package/components/dd-parse/props.js +57 -0
  64. package/components/dd-popover/dd-popover.vue +10 -10
  65. package/components/dd-popover-item/dd-popover-item.vue +3 -3
  66. package/components/dd-popup/dd-popup.vue +5 -5
  67. package/components/dd-poster/dd-poster.vue +695 -0
  68. package/components/dd-progress/dd-progress.vue +3 -3
  69. package/components/dd-pull-refresh/dd-pull-refresh.vue +3 -3
  70. package/components/dd-qrcode/dd-qrcode.vue +509 -0
  71. package/components/dd-qrcode/qrcode.js +1283 -0
  72. package/components/dd-radio/dd-radio.vue +19 -20
  73. package/components/dd-radio-group/dd-radio-group.vue +53 -0
  74. package/components/dd-rate/dd-rate.vue +1 -1
  75. package/components/dd-room-card/dd-room-card.vue +3 -3
  76. package/components/dd-search-bar/dd-search-bar.vue +8 -8
  77. package/components/dd-segmented-tab/dd-segmented-tab.vue +6 -6
  78. package/components/dd-signature/dd-signature.vue +513 -0
  79. package/components/dd-skeleton/dd-skeleton.vue +1 -1
  80. package/components/dd-slider/dd-slider.vue +4 -4
  81. package/components/dd-stat-card/dd-stat-card.vue +5 -5
  82. package/components/dd-step/dd-step.vue +11 -11
  83. package/components/dd-stepper/dd-stepper.vue +6 -6
  84. package/components/dd-swipe-action/dd-swipe-action.vue +1 -1
  85. package/components/dd-swipeable-tab/dd-swipeable-tab.vue +1 -1
  86. package/components/dd-tabbar-item/dd-tabbar-item.vue +8 -8
  87. package/components/dd-tag/dd-tag.vue +17 -1
  88. package/components/dd-text/dd-text.vue +250 -0
  89. package/components/dd-text/props.js +120 -0
  90. package/components/dd-text/text.js +30 -0
  91. package/components/dd-text/value.js +87 -0
  92. package/components/dd-toast/dd-toast.vue +2 -2
  93. package/components/dd-upload/dd-upload.vue +4 -4
  94. package/components/dd-workorder-card/dd-workorder-card.vue +237 -0
  95. package/index.ts +50 -9
  96. package/libs/config/color.js +16 -0
  97. package/libs/config/config.js +25 -0
  98. package/libs/config/props.js +185 -0
  99. package/libs/config/zIndex.js +20 -0
  100. package/libs/function/digit.js +167 -0
  101. package/libs/function/index.js +932 -0
  102. package/libs/function/test.js +327 -0
  103. package/libs/i18n/index.d.ts +2 -0
  104. package/libs/i18n/index.js +89 -0
  105. package/libs/i18n/locales/zh-Hans.js +86 -0
  106. package/libs/mixin/button.js +18 -0
  107. package/libs/mixin/mixin.js +44 -0
  108. package/libs/mixin/mpMixin.js +13 -0
  109. package/libs/mixin/openType.js +27 -0
  110. package/libs/utils.ts +462 -0
  111. package/libs/vue.js +3 -0
  112. package/package.json +1 -1
  113. package/scss/_dd-shared.scss +40 -0
  114. package/scss/_variables.scss +4 -1
package/libs/utils.ts CHANGED
@@ -104,3 +104,465 @@ export function getRect(selector: string): Promise<UniApp.NodeInfo> {
104
104
  export function getEventValue(e: any): string {
105
105
  return e?.detail?.value ?? e?.target?.value ?? ''
106
106
  }
107
+
108
+ // ============================================================
109
+ // 日期工具(供 dd-calendar 使用)
110
+ // ============================================================
111
+ export function pad2(n: number): string {
112
+ return n < 10 ? '0' + n : '' + n
113
+ }
114
+
115
+ export function dateFormat(d: Date, sep = '-'): string {
116
+ return `${d.getFullYear()}${sep}${pad2(d.getMonth() + 1)}${sep}${pad2(d.getDate())}`
117
+ }
118
+
119
+ export function parseDate(s: string): Date {
120
+ const [y, m, d] = s.split('-').map(Number)
121
+ return new Date(y, (m || 1) - 1, d || 1)
122
+ }
123
+
124
+ export function addDays(s: string, days: number): string {
125
+ const d = parseDate(s)
126
+ d.setDate(d.getDate() + days)
127
+ return dateFormat(d)
128
+ }
129
+
130
+ // 某月首日为周几(0=周日)
131
+ export function firstDayOfMonth(year: number, month: number): number {
132
+ return new Date(year, month, 1).getDay()
133
+ }
134
+
135
+ export function daysInMonth(year: number, month: number): number {
136
+ return new Date(year, month + 1, 0).getDate()
137
+ }
138
+
139
+ // ============================================================
140
+ // 二维码(QR Code)生成 — 纯 JS,无三方依赖
141
+ // port: 移植自 Project Nayuki QR Code generator(public domain,qrcodegen)。
142
+ // https://www.nayuki.io/page/qr-code-generator-library
143
+ // 保留核心正确性(ECC 分组/交织、8 掩码惩罚择优、对齐/版本/格式图形),
144
+ // 裁剪为 byte 模式 + 单段文本,兼容 H5/微信/抖音/App 的 uni canvas 渲染。
145
+ // ============================================================
146
+
147
+ export type QrEcc = 'L' | 'M' | 'Q' | 'H'
148
+
149
+ export interface QrSegment {
150
+ modeBits: number
151
+ numChars: number
152
+ dataBits: number[]
153
+ }
154
+
155
+ export interface QRResult {
156
+ size: number // 边长(模块数,不含静区)
157
+ modules: boolean[][] // 二维布尔矩阵,true=暗模块
158
+ }
159
+
160
+ // ECC 每块码字数表(version 1-40 × [L,M,Q,H])
161
+ // prettier-ignore
162
+ const ECC_CODEWORDS_PER_BLOCK = [
163
+ [7, 10, 13, 17], [10, 16, 22, 28], [15, 26, 18, 22], [20, 18, 26, 16],
164
+ [26, 24, 18, 22], [18, 16, 24, 28], [20, 18, 18, 26], [24, 22, 22, 26],
165
+ [30, 22, 20, 24], [18, 26, 24, 28], [20, 30, 28, 24], [24, 22, 26, 28],
166
+ [26, 22, 24, 22], [30, 24, 20, 24], [22, 24, 30, 24], [24, 28, 24, 30],
167
+ [28, 28, 28, 28], [30, 26, 28, 28], [28, 26, 26, 26], [28, 26, 30, 28],
168
+ [28, 26, 28, 30], [28, 28, 30, 24], [30, 28, 30, 30], [30, 28, 30, 30],
169
+ [26, 28, 30, 30], [28, 28, 28, 30], [30, 28, 30, 30], [30, 28, 30, 30],
170
+ [30, 28, 30, 30], [30, 28, 30, 30], [30, 28, 30, 30], [30, 28, 30, 30],
171
+ [30, 28, 30, 30], [30, 28, 30, 30], [30, 28, 30, 30], [30, 28, 30, 30],
172
+ [30, 28, 30, 30], [30, 28, 30, 30], [30, 28, 30, 30], [30, 28, 30, 30],
173
+ ]
174
+
175
+ // 纠错块数表(version 1-40 × [L,M,Q,H])
176
+ // prettier-ignore
177
+ const NUM_ERROR_CORRECTION_BLOCKS = [
178
+ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 2, 2], [1, 2, 2, 4],
179
+ [1, 2, 4, 4], [2, 4, 4, 4], [2, 4, 6, 5], [2, 4, 6, 6],
180
+ [2, 5, 8, 8], [4, 5, 8, 8], [4, 5, 8, 11], [4, 8, 10, 11],
181
+ [4, 9, 12, 16], [4, 9, 16, 16], [6, 10, 12, 18], [6, 10, 17, 16],
182
+ [6, 11, 16, 19], [6, 13, 18, 21], [7, 14, 21, 25], [8, 16, 20, 25],
183
+ [8, 17, 23, 25], [9, 17, 23, 34], [9, 18, 25, 30], [10, 20, 27, 32],
184
+ [12, 21, 29, 35], [12, 23, 34, 37], [12, 25, 34, 40], [13, 26, 35, 42],
185
+ [14, 28, 38, 45], [15, 29, 40, 48], [16, 31, 43, 51], [17, 33, 45, 54],
186
+ [18, 35, 48, 57], [19, 37, 51, 60], [19, 38, 53, 63], [20, 40, 56, 66],
187
+ [21, 43, 59, 70], [22, 45, 62, 74], [24, 47, 65, 77], [25, 49, 68, 81],
188
+ ]
189
+
190
+ // ECC → 5bit 格式信息数据位(低 3 位为掩码编号,此处占位为 0)
191
+ const ECC_FORMAT_BITS: { [k in QrEcc]: number } = { L: 1, M: 0, Q: 3, H: 2 }
192
+
193
+ function getBit(x: number, i: number): boolean {
194
+ return ((x >>> i) & 1) !== 0
195
+ }
196
+
197
+ // GF(256) 乘法(本原多项式 0x11D)
198
+ function gfMul(x: number, y: number): number {
199
+ let result = 0
200
+ let a = x
201
+ let b = y
202
+ for (let i = 0; i < 8; i++) {
203
+ if (b & 1) result ^= a
204
+ b >>>= 1
205
+ a = (a << 1) ^ (a & 0x80 ? 0x11d : 0)
206
+ a &= 0xff
207
+ }
208
+ return result
209
+ }
210
+
211
+ // Reed-Solomon 除式(生成多项式)
212
+ function rsDivisor(degree: number): number[] {
213
+ const result = [1]
214
+ let root = 1
215
+ for (let i = 0; i < degree; i++) {
216
+ for (let j = 0; j < result.length; j++) {
217
+ result[j] = gfMul(result[j], root)
218
+ if (j + 1 < result.length) result[j + 1] ^= result[j]
219
+ }
220
+ root = gfMul(root, 0x02)
221
+ }
222
+ return result
223
+ }
224
+
225
+ function rsRemainder(data: number[], divisor: number[]): number[] {
226
+ const result = new Array(divisor.length).fill(0)
227
+ for (const b of data) {
228
+ const factor = b ^ result.shift()!
229
+ result.push(0)
230
+ for (let i = 0; i < result.length; i++) result[i] ^= gfMul(divisor[i], factor)
231
+ }
232
+ return result
233
+ }
234
+
235
+ // 整数补位
236
+ function appendBits(val: number, len: number, bb: number[]): void {
237
+ for (let i = len - 1; i >= 0; i--) bb.push((val >>> i) & 1)
238
+ }
239
+
240
+ // byte 模式分段
241
+ function makeByteSegment(data: string): QrSegment {
242
+ const bytes = utf8Bytes(data)
243
+ const bits: number[] = []
244
+ for (const b of bytes) appendBits(b, 8, bits)
245
+ return { modeBits: 0b0100, numChars: bytes.length, dataBits: bits }
246
+ }
247
+
248
+ function utf8Bytes(str: string): number[] {
249
+ const enc = typeof TextEncoder !== 'undefined' ? new TextEncoder() : null
250
+ if (enc) return Array.from(enc.encode(str))
251
+ const bytes: number[] = []
252
+ for (let i = 0; i < str.length; i++) {
253
+ let c = str.charCodeAt(i)
254
+ if (c < 0x80) bytes.push(c)
255
+ else if (c < 0x800) bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f))
256
+ else if (c >= 0xd800 && c < 0xdc00) {
257
+ const hi = c
258
+ c = str.charCodeAt(++i)
259
+ const code = 0x10000 + ((hi - 0xd800) << 10) + (c - 0xdc00)
260
+ bytes.push(0xf0 | (code >> 18), 0x80 | ((code >> 12) & 0x3f), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f))
261
+ } else bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f))
262
+ }
263
+ return bytes
264
+ }
265
+
266
+ function getNumRawDataModules(ver: number): number {
267
+ let result = (16 * ver + 128) * ver + 64
268
+ if (ver >= 2) {
269
+ const n = Math.floor(ver / 7) + 2
270
+ result -= (25 * n - 10) * n
271
+ if (ver >= 7) result -= 36
272
+ }
273
+ return result
274
+ }
275
+
276
+ function getNumDataCodewords(ver: number, ecl: QrEcc): number {
277
+ const eclIdx = ECC_INDEX[ecl]
278
+ return Math.floor(getNumRawDataModules(ver) / 8) -
279
+ ECC_CODEWORDS_PER_BLOCK[ver - 1][eclIdx] * NUM_ERROR_CORRECTION_BLOCKS[ver - 1][eclIdx]
280
+ }
281
+ const ECC_INDEX: { [k in QrEcc]: number } = { L: 0, M: 1, Q: 2, H: 3 }
282
+
283
+ function addEccAndInterleave(data: number[], ver: number, ecl: QrEcc): number[] {
284
+ const numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ver - 1][ECC_INDEX[ecl]]
285
+ const blockEccLen = ECC_CODEWORDS_PER_BLOCK[ver - 1][ECC_INDEX[ecl]]
286
+ const rawCodewords = Math.floor(getNumRawDataModules(ver) / 8)
287
+ const numShortBlocks = numBlocks - (rawCodewords % numBlocks)
288
+ const shortBlockLen = Math.floor(rawCodewords / numBlocks)
289
+ const blocks: number[][] = []
290
+ const rsDiv = rsDivisor(blockEccLen)
291
+ let k = 0
292
+ for (let i = 0; i < numBlocks; i++) {
293
+ const datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)
294
+ const dat = data.slice(k, k + datLen)
295
+ k += datLen
296
+ const ecc = rsRemainder(dat, rsDiv)
297
+ if (i < numShortBlocks) blocks.push(dat.concat(ecc))
298
+ else blocks.push(dat.concat(ecc))
299
+ }
300
+ // 交织
301
+ const result: number[] = []
302
+ const maxLen = blocks[numBlocks - 1].length
303
+ for (let i = 0; i < maxLen; i++) {
304
+ for (let j = 0; j < numBlocks; j++) {
305
+ if (i < blocks[j].length) result.push(blocks[j][i])
306
+ }
307
+ }
308
+ return result
309
+ }
310
+
311
+ // 主入口
312
+ export function generateQR(text: string, ecc: QrEcc = 'M'): QRResult {
313
+ const seg = makeByteSegment(text)
314
+
315
+ // 选择最小版本
316
+ let minVer = 1
317
+ ;(function () {
318
+ for (let v = 1; v <= 40; v++) {
319
+ const dataCap = getNumDataCodewords(v, ecc)
320
+ const segBitsLen = seg.modeBits === 0b0100 ? 4 + (v < 10 ? 8 : 16) + seg.dataBits.length : 0
321
+ if (segBitsLen <= dataCap * 8) {
322
+ minVer = v
323
+ return
324
+ }
325
+ }
326
+ minVer = 40
327
+ })()
328
+
329
+ // 组装数据码字
330
+ const bb: number[] = []
331
+ appendBits(seg.modeBits, 4, bb)
332
+ appendBits(seg.numChars, minVer < 10 ? 8 : 16, bb)
333
+ for (const b of seg.dataBits) bb.push(b)
334
+ const dataCapBits = getNumDataCodewords(minVer, ecc) * 8
335
+ appendBits(0, Math.min(4, dataCapBits - bb.length), bb)
336
+ appendBits(0, (8 - (bb.length % 8)) % 8, bb)
337
+ const dataBytes: number[] = []
338
+ for (let i = 0; i < bb.length; i += 8) {
339
+ let b = 0
340
+ for (let j = 0; j < 8; j++) b = (b << 1) | bb[i + j]
341
+ dataBytes.push(b)
342
+ }
343
+ const padBytes = [0xec, 0x11]
344
+ let pi = 0
345
+ while (dataBytes.length < getNumDataCodewords(minVer, ecc)) {
346
+ dataBytes.push(padBytes[pi % 2])
347
+ pi++
348
+ }
349
+ const allCodewords = addEccAndInterleave(dataBytes, minVer, ecc)
350
+
351
+ return buildQrMatrix(minVer, ecc, allCodewords)
352
+ }
353
+
354
+ function buildQrMatrix(ver: number, ecl: QrEcc, dataCodewords: number[]): QRResult {
355
+ const size = ver * 4 + 17
356
+ let modules = Array.from({ length: size }, () => new Array<boolean>(size).fill(false))
357
+ let isFunction = Array.from({ length: size }, () => new Array<boolean>(size).fill(false))
358
+
359
+ function setFunctionModule(r: number, c: number, isDark: boolean): boolean {
360
+ if (r < 0 || c < 0 || r >= size || c >= size) return false
361
+ modules[r][c] = isDark
362
+ isFunction[r][c] = true
363
+ return true
364
+ }
365
+
366
+ function drawFinder(r0: number, c0: number): void {
367
+ for (let y = -1; y <= 7; y++) {
368
+ for (let x = -1; x <= 7; x++) {
369
+ const inside = y >= 0 && y <= 6 && x >= 0 && x <= 6
370
+ const dark = inside && (x === 0 || x === 6 || y === 0 || y === 6 || (x >= 2 && x <= 4 && y >= 2 && y <= 4))
371
+ // 7×7 finder 以 (r0,c0) 为中心,相对 (y,x)∈0..6 → 绝对 r0-3..r0+3;
372
+ // y/x 的 -1/7 一圈(outside)为浅色分隔区(separator),同样标记为 function 以阻止数据写入
373
+ setFunctionModule(r0 + y - 3, c0 + x - 3, dark)
374
+ }
375
+ }
376
+ }
377
+
378
+ function drawAlignment(r0: number, c0: number): void {
379
+ for (let y = -2; y <= 2; y++) {
380
+ for (let x = -2; x <= 2; x++) {
381
+ const dark = x === -2 || x === 2 || y === -2 || y === 2 || (x === 0 && y === 0)
382
+ setFunctionModule(r0 + y, c0 + x, dark)
383
+ }
384
+ }
385
+ }
386
+
387
+ function drawTiming(): void {
388
+ for (let i = 8; i < size - 8; i++) {
389
+ if (modules[6][i] === undefined) continue
390
+ setFunctionModule(6, i, i % 2 === 0)
391
+ setFunctionModule(i, 6, i % 2 === 0)
392
+ }
393
+ }
394
+
395
+ function drawFormatBits(mask: number): void {
396
+ const data = (ECC_FORMAT_BITS[ecl] << 3) | mask
397
+ let rem = data
398
+ for (let i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >>> 9) * 0x537)
399
+ const fmt = ((data << 10) | rem) ^ 0x5412
400
+ for (let i = 0; i <= 5; i++) setFunctionModule(8, i, getBit(fmt, i))
401
+ setFunctionModule(8, 7, getBit(fmt, 6))
402
+ setFunctionModule(8, 8, getBit(fmt, 7))
403
+ setFunctionModule(7, 8, getBit(fmt, 8))
404
+ for (let i = 9; i < 15; i++) setFunctionModule(14 - i, 8, getBit(fmt, i))
405
+ for (let i = 0; i < 8; i++) setFunctionModule(size - 1 - i, 8, getBit(fmt, i))
406
+ for (let i = 8; i < 15; i++) setFunctionModule(8, size - 15 + i, getBit(fmt, i))
407
+ setFunctionModule(8, size - 8, true) // dark module
408
+ }
409
+
410
+ function drawVersion(ver2: number): void {
411
+ if (ver2 < 7) return
412
+ const g = 0x1f25
413
+ let rem = ver2
414
+ for (let i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >>> 11) * g)
415
+ const bits = (ver2 << 12) | rem
416
+ for (let i = 0; i < 18; i++) {
417
+ const bit = getBit(bits, i)
418
+ const a = size - 11 + (i % 3)
419
+ const b = Math.floor(i / 3)
420
+ setFunctionModule(a, b, bit)
421
+ setFunctionModule(b, a, bit)
422
+ }
423
+ }
424
+
425
+ // 功能图形
426
+ drawFinder(3, 3)
427
+ drawFinder(size - 4, 3)
428
+ drawFinder(3, size - 4)
429
+
430
+ // 对齐图案位置
431
+ const alignmentPositions = (() => {
432
+ if (ver === 1) return []
433
+ const numAlign = Math.floor(ver / 7) + 2
434
+ const step = ver === 32 ? 26 : Math.ceil((ver * 4 + 4) / (numAlign * 2 - 2)) * 2
435
+ const positions = [6]
436
+ for (let pos = size - 7; positions.length < numAlign; pos -= step) positions.splice(1, 0, pos)
437
+ return positions
438
+ })()
439
+
440
+ for (const a of alignmentPositions) {
441
+ for (const b of alignmentPositions) {
442
+ if ((a === 6 && b === 6) || (a === 6 && b === size - 7) || (a === size - 7 && b === 6)) continue
443
+ drawAlignment(a, b)
444
+ }
445
+ }
446
+
447
+ drawTiming()
448
+ // 掩码选择:遍历 8 种掩码,取 penalty 最低者
449
+ let bestMask = 0
450
+ let bestPenalty = Infinity
451
+ for (let mask = 0; mask < 8; mask++) {
452
+ // 重新构建空白矩阵
453
+ modules = Array.from({ length: size }, () => new Array<boolean>(size).fill(false))
454
+ isFunction = Array.from({ length: size }, () => new Array<boolean>(size).fill(false))
455
+ drawFinder(3, 3)
456
+ drawFinder(size - 4, 3)
457
+ drawFinder(3, size - 4)
458
+ for (const a of alignmentPositions) for (const b of alignmentPositions) {
459
+ if ((a === 6 && b === 6) || (a === 6 && b === size - 7) || (a === size - 7 && b === 6)) continue
460
+ drawAlignment(a, b)
461
+ }
462
+ drawTiming()
463
+ drawFormatBits(mask)
464
+ drawVersion(ver)
465
+ drawCodewords(dataCodewords, mask, modules, isFunction, size)
466
+ const penalty = getPenaltyScore(modules, isFunction, size)
467
+ if (penalty < bestPenalty) {
468
+ bestPenalty = penalty
469
+ bestMask = mask
470
+ }
471
+ }
472
+
473
+ // 用最优掩码最终重建
474
+ modules = Array.from({ length: size }, () => new Array<boolean>(size).fill(false))
475
+ isFunction = Array.from({ length: size }, () => new Array<boolean>(size).fill(false))
476
+ drawFinder(3, 3)
477
+ drawFinder(size - 4, 3)
478
+ drawFinder(3, size - 4)
479
+ for (const a of alignmentPositions) for (const b of alignmentPositions) {
480
+ if ((a === 6 && b === 6) || (a === 6 && b === size - 7) || (a === size - 7 && b === 6)) continue
481
+ drawAlignment(a, b)
482
+ }
483
+ drawTiming()
484
+ drawFormatBits(bestMask)
485
+ drawVersion(ver)
486
+ drawCodewords(dataCodewords, bestMask, modules, isFunction, size)
487
+
488
+ return { size, modules }
489
+ }
490
+
491
+ function drawCodewords(
492
+ data: number[], mask: number,
493
+ modules: boolean[][], isFunction: boolean[][], size: number
494
+ ): void {
495
+ let i = 0
496
+ let right = size - 1
497
+ while (right >= 1) {
498
+ if (right === 6) right = 5
499
+ for (let vert = 0; vert < size; vert++) {
500
+ const y = (right + 1) % 2 === 0 ? size - 1 - vert : vert
501
+ for (let j = 0; j < 2; j++) {
502
+ const x = right - j
503
+ if (isFunction[y][x]) continue
504
+ let dark = false
505
+ if (i < data.length * 8) dark = getBit(data[i >>> 3], 7 - (i & 7))
506
+ if (dark) modules[y][x] = dark
507
+ // 应用数据掩码
508
+ if (!isFunction[y][x]) {
509
+ let invert = false
510
+ switch (mask) {
511
+ case 0: invert = (y + x) % 2 === 0; break
512
+ case 1: invert = y % 2 === 0; break
513
+ case 2: invert = x % 3 === 0; break
514
+ case 3: invert = (y + x) % 3 === 0; break
515
+ case 4: invert = (Math.floor(y / 2) + Math.floor(x / 3)) % 2 === 0; break
516
+ case 5: invert = ((y * x) % 2) + ((y * x) % 3) === 0; break
517
+ case 6: invert = (((y * x) % 2) + ((y * x) % 3)) % 2 === 0; break
518
+ case 7: invert = (((y + x) % 2) + ((y * x) % 3)) % 2 === 0; break
519
+ }
520
+ modules[y][x] = modules[y][x] !== invert
521
+ }
522
+ i++
523
+ }
524
+ }
525
+ right -= 2
526
+ }
527
+ }
528
+
529
+ // 掩码质量评分(仅用于在 8 种合法掩码中择优,无需与标准惩罚规则完全一致;
530
+ // 任一合法掩码都可被解码器正确识别,score 越低视觉越规整)
531
+ function getPenaltyScore(modules: boolean[][], isFunction: boolean[][], size: number): number {
532
+ let score = 0
533
+ // 行内连续同色惩罚
534
+ for (let y = 0; y < size; y++) {
535
+ let run = 0
536
+ for (let x = 0; x < size; x++) {
537
+ if (isFunction[y][x]) { run = 0; continue }
538
+ const dark = modules[y][x]
539
+ if (x === 0 || modules[y][x - 1] !== dark) run = 1
540
+ else {
541
+ run++
542
+ if (run >= 5) score += 1
543
+ }
544
+ }
545
+ }
546
+ // 列内连续同色惩罚
547
+ for (let x = 0; x < size; x++) {
548
+ let run = 0
549
+ for (let y = 0; y < size; y++) {
550
+ if (isFunction[y][x]) { run = 0; continue }
551
+ const dark = modules[y][x]
552
+ if (y === 0 || modules[y - 1][x] !== dark) run = 1
553
+ else {
554
+ run++
555
+ if (run >= 5) score += 1
556
+ }
557
+ }
558
+ }
559
+ // 2×2 同色方块惩罚
560
+ for (let y = 0; y < size - 1; y++) {
561
+ for (let x = 0; x < size - 1; x++) {
562
+ if (isFunction[y][x] || isFunction[y][x + 1] || isFunction[y + 1][x] || isFunction[y + 1][x + 1]) continue
563
+ const r = modules[y][x]
564
+ if (r === modules[y][x + 1] && r === modules[y + 1][x] && r === modules[y + 1][x + 1]) score += 3
565
+ }
566
+ }
567
+ return score
568
+ }
package/libs/vue.js ADDED
@@ -0,0 +1,3 @@
1
+ export const defineMixin = (options) => {
2
+ return options
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@didaoktv/didaoui-uniapp",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "帝到KTV UniApp 组件库",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",
@@ -0,0 +1,40 @@
1
+ // 通过scss的mixin功能,把原来需要写4行的css,变成一行
2
+ // 目的是保持代码干净整洁,不至于在nvue下,到处都要写display:flex的条件编译
3
+ @mixin flex($direction: row) {
4
+ /* #ifndef APP-NVUE */
5
+ display: flex;
6
+ /* #endif */
7
+ flex-direction: $direction;
8
+ }
9
+
10
+ // —— 以下为移植组件引用的工具类(就地生成,避免全局注入) ——
11
+ // 按钮重置
12
+ .dd-reset-button {
13
+ padding: 0;
14
+ background-color: transparent;
15
+ font-size: inherit;
16
+ line-height: inherit;
17
+ color: inherit;
18
+ }
19
+
20
+ .dd-reset-button::after {
21
+ border: none;
22
+ }
23
+
24
+ // 超出行数省略号(dd-line-N)
25
+ @for $i from 1 through 10 {
26
+ .dd-line-#{$i} {
27
+ /* #ifdef APP-NVUE */
28
+ lines: $i;
29
+ text-overflow: ellipsis;
30
+ overflow: hidden;
31
+ flex: 1;
32
+ /* #endif */
33
+ /* #ifndef APP-NVUE */
34
+ display: -webkit-box;
35
+ -webkit-box-orient: vertical;
36
+ -webkit-line-clamp: $i;
37
+ overflow: hidden;
38
+ /* #endif */
39
+ }
40
+ }
@@ -155,7 +155,7 @@ $dd-text-glow: rgba(255, 255, 255, 0.3);
155
155
  $dd-font-display: 'Playfair Display', serif;
156
156
  $dd-font-heading: 'Noto Sans SC', sans-serif;
157
157
  $dd-font-body: 'Noto Sans SC', sans-serif;
158
- $dd-font-mono: 'JetBrains Mono', monospace;
158
+ $dd-font-mono: 'Noto Sans SC', sans-serif;
159
159
 
160
160
  // === 字号 (from css.json font.size) ===
161
161
  $dd-font-size-display: 32px;
@@ -166,6 +166,7 @@ $dd-font-size-h4: 16px;
166
166
  $dd-font-size-body: 14px;
167
167
  $dd-font-size-lead: 16px;
168
168
  $dd-font-size-caption: 12px;
169
+ $dd-font-size-overline: 10px;
169
170
  $dd-font-size-mono: 14px;
170
171
 
171
172
  // === 字重 (from css.json font.weight) ===
@@ -177,6 +178,7 @@ $dd-font-weight-h4: 700;
177
178
  $dd-font-weight-body: 500;
178
179
  $dd-font-weight-lead: 500;
179
180
  $dd-font-weight-caption: 500;
181
+ $dd-font-weight-overline: 500;
180
182
  $dd-font-weight-mono: 600;
181
183
 
182
184
  // === 行高 (from css.json font.lineHeight) ===
@@ -188,6 +190,7 @@ $dd-line-height-h4: 1.4;
188
190
  $dd-line-height-body: 1.6;
189
191
  $dd-line-height-lead: 1.7;
190
192
  $dd-line-height-caption: 1.5;
193
+ $dd-line-height-overline: 1.4;
191
194
  $dd-line-height-mono: 1.6;
192
195
 
193
196
  // === 间距 (from css.json spacing) ===