@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.
- package/README.md +16 -7
- package/components/dd-action-sheet/dd-action-sheet.vue +3 -3
- package/components/dd-album/album.js +19 -0
- package/components/dd-album/dd-album.vue +345 -0
- package/components/dd-album/props.js +89 -0
- package/components/dd-avatar/avatar.js +19 -0
- package/components/dd-avatar/dd-avatar.vue +172 -160
- package/components/dd-avatar/props.js +84 -0
- package/components/dd-avatar-group/avatarGroup.js +14 -0
- package/components/dd-avatar-group/dd-avatar-group.vue +110 -0
- package/components/dd-avatar-group/props.js +57 -0
- package/components/dd-badge/dd-badge.vue +2 -2
- package/components/dd-barcode/dd-barcode.vue +1030 -0
- package/components/dd-bill-detail/dd-bill-detail.vue +265 -0
- package/components/dd-button/dd-button.vue +17 -17
- package/components/dd-calendar/dd-calendar.vue +357 -0
- package/components/dd-canvas/dd-canvas.vue +1088 -0
- package/components/dd-capsule-button/dd-capsule-button.vue +6 -6
- package/components/dd-car-keyboard/carKeyboard.js +6 -0
- package/components/dd-car-keyboard/dd-car-keyboard.vue +315 -0
- package/components/dd-car-keyboard/props.js +19 -0
- package/components/dd-cascader/dd-cascader.vue +405 -0
- package/components/dd-cell/dd-cell.vue +50 -23
- package/components/dd-cell-group/dd-cell-group.vue +32 -25
- package/components/dd-champion-card/dd-champion-card.vue +4 -4
- package/components/dd-checkbox/dd-checkbox.vue +30 -39
- package/components/dd-checkbox-group/dd-checkbox-group.vue +67 -0
- package/components/dd-copy/dd-copy.vue +74 -0
- package/components/dd-coupon/dd-coupon.vue +368 -0
- package/components/dd-cropper/dd-cropper.vue +1297 -0
- package/components/dd-dialog/dd-dialog.vue +1 -1
- package/components/dd-divider/dd-divider.vue +3 -3
- package/components/dd-dropdown-item/dd-dropdown-item.vue +5 -5
- package/components/dd-empty-state/dd-empty-state.vue +1 -1
- package/components/dd-field/dd-field.vue +531 -106
- package/components/dd-form/dd-form.vue +116 -0
- package/components/dd-form/rules.ts +84 -0
- package/components/dd-goods-sku/dd-goods-sku.vue +434 -0
- package/components/dd-icon/dd-icon.vue +2 -2
- package/components/dd-image/dd-image.vue +4 -4
- package/components/dd-input/dd-input.vue +5 -5
- package/components/dd-keyboard/dd-keyboard.vue +178 -0
- package/components/dd-keyboard/keyboard.js +22 -0
- package/components/dd-keyboard/props.js +89 -0
- package/components/dd-link/dd-link.vue +87 -0
- package/components/dd-link/link.js +18 -0
- package/components/dd-link/props.js +44 -0
- package/components/dd-list-cell/dd-list-cell.vue +4 -4
- package/components/dd-loading/dd-loading.vue +1 -1
- package/components/dd-loadmore/dd-loadmore.vue +2 -2
- package/components/dd-markdown/dd-markdown.vue +344 -0
- package/components/dd-markdown/marked.esm.mjs +7 -0
- package/components/dd-mini-program-navbar/dd-mini-program-navbar.vue +9 -9
- package/components/dd-navigation/dd-navigation.vue +5 -5
- package/components/dd-number-keyboard/dd-number-keyboard.vue +200 -0
- package/components/dd-number-keyboard/numberKeyboard.js +8 -0
- package/components/dd-number-keyboard/props.js +24 -0
- package/components/dd-parse/dd-parse.vue +534 -0
- package/components/dd-parse/node/handler.wxs +26 -0
- package/components/dd-parse/node/node.vue +603 -0
- package/components/dd-parse/parse.js +13 -0
- package/components/dd-parse/parser.js +1400 -0
- package/components/dd-parse/props.js +57 -0
- package/components/dd-popover/dd-popover.vue +10 -10
- package/components/dd-popover-item/dd-popover-item.vue +3 -3
- package/components/dd-popup/dd-popup.vue +5 -5
- package/components/dd-poster/dd-poster.vue +695 -0
- package/components/dd-progress/dd-progress.vue +3 -3
- package/components/dd-pull-refresh/dd-pull-refresh.vue +3 -3
- package/components/dd-qrcode/dd-qrcode.vue +509 -0
- package/components/dd-qrcode/qrcode.js +1283 -0
- package/components/dd-radio/dd-radio.vue +19 -20
- package/components/dd-radio-group/dd-radio-group.vue +53 -0
- package/components/dd-rate/dd-rate.vue +1 -1
- package/components/dd-room-card/dd-room-card.vue +3 -3
- package/components/dd-search-bar/dd-search-bar.vue +8 -8
- package/components/dd-segmented-tab/dd-segmented-tab.vue +6 -6
- package/components/dd-signature/dd-signature.vue +513 -0
- package/components/dd-skeleton/dd-skeleton.vue +1 -1
- package/components/dd-slider/dd-slider.vue +4 -4
- package/components/dd-stat-card/dd-stat-card.vue +5 -5
- package/components/dd-step/dd-step.vue +11 -11
- package/components/dd-stepper/dd-stepper.vue +6 -6
- package/components/dd-swipe-action/dd-swipe-action.vue +1 -1
- package/components/dd-swipeable-tab/dd-swipeable-tab.vue +1 -1
- package/components/dd-tabbar-item/dd-tabbar-item.vue +8 -8
- package/components/dd-tag/dd-tag.vue +17 -1
- package/components/dd-text/dd-text.vue +250 -0
- package/components/dd-text/props.js +120 -0
- package/components/dd-text/text.js +30 -0
- package/components/dd-text/value.js +87 -0
- package/components/dd-toast/dd-toast.vue +2 -2
- package/components/dd-upload/dd-upload.vue +4 -4
- package/components/dd-workorder-card/dd-workorder-card.vue +237 -0
- package/index.ts +50 -9
- package/libs/config/color.js +16 -0
- package/libs/config/config.js +25 -0
- package/libs/config/props.js +185 -0
- package/libs/config/zIndex.js +20 -0
- package/libs/function/digit.js +167 -0
- package/libs/function/index.js +932 -0
- package/libs/function/test.js +327 -0
- package/libs/i18n/index.d.ts +2 -0
- package/libs/i18n/index.js +89 -0
- package/libs/i18n/locales/zh-Hans.js +86 -0
- package/libs/mixin/button.js +18 -0
- package/libs/mixin/mixin.js +44 -0
- package/libs/mixin/mpMixin.js +13 -0
- package/libs/mixin/openType.js +27 -0
- package/libs/utils.ts +462 -0
- package/libs/vue.js +3 -0
- package/package.json +1 -1
- package/scss/_dd-shared.scss +40 -0
- 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
package/package.json
CHANGED
|
@@ -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
|
+
}
|
package/scss/_variables.scss
CHANGED
|
@@ -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: '
|
|
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) ===
|