first commit

This commit is contained in:
Mrx
2026-05-16 15:47:07 +08:00
commit 03de10f800
146 changed files with 33663 additions and 0 deletions

24
src/utils/crypto.ts Normal file
View File

@@ -0,0 +1,24 @@
import CryptoJS from 'crypto-js'
/** 与 tyc-webview-v2 `utils/crypto.js` 一致AES-CBCIV 前置后 Base64 */
export function aesEncrypt(plainText: string, hexKey: string): string {
const key = CryptoJS.enc.Hex.parse(hexKey)
const iv = generateRandomIV()
const encrypted = CryptoJS.AES.encrypt(plainText, key, {
iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC,
})
const ivAndCipherText = iv.concat(encrypted.ciphertext)
return CryptoJS.enc.Base64.stringify(ivAndCipherText)
}
function generateRandomIV() {
const iv: number[] = []
for (let i = 0; i < 16; i++)
iv.push(Math.floor(Math.random() * 256))
return CryptoJS.enc.Hex.parse(iv.map(b => b.toString(16).padStart(2, '0')).join(''))
}
/** 与 H5 `InquireForm.vue` 中 `aesEncrypt(..., key)` 使用的密钥一致 */
export const QUERY_PAYLOAD_AES_HEX_KEY = 'ff83609b2b24fc73196aac3d3dfb874f'

16
src/utils/session.js Normal file
View File

@@ -0,0 +1,16 @@
/** 对齐 tyc-webview-v2 登录成功后的本地存储字段 */
export function saveAuthSession(payload) {
uni.setStorageSync('token', payload.accessToken)
uni.setStorageSync('refreshAfter', String(payload.refreshAfter))
uni.setStorageSync('accessExpire', String(payload.accessExpire))
}
export function hasToken() {
try {
const t = uni.getStorageSync('token')
return typeof t === 'string' && t.length > 0
}
catch {
return false
}
}

View File

@@ -0,0 +1,43 @@
/**
* 将 /query/example、/query/orderNo/:no 等返回的 query_data 项规范为壳层使用的结构。
* 与 H5 BaseReport 约定一致:每项 `data` 多为 `{ apiID, data: 业务体 }`。
* @returns {Array<{ apiId: string, payload: any, sort: number, featureName: string }>} 按 sort 排序后的行列表
*/
export function normalizeVehicleQueryData(raw) {
if (!Array.isArray(raw))
return []
const rows = []
for (const item of raw) {
if (!item || typeof item !== 'object')
continue
let sort = 0
let featureName = ''
const feat = item.feature
if (feat && typeof feat === 'object') {
sort = Number(feat.sort ?? 0)
featureName = String(feat.featureName ?? '')
}
const d = item.data
let apiId = ''
let payload = d
if (d != null && typeof d === 'object' && !Array.isArray(d)) {
apiId = String(d.apiID ?? d.apiId ?? '')
if ('data' in d)
payload = d.data
}
if (!apiId) {
apiId = '__UNLABELED__'
payload = d
}
rows.push({ apiId, payload, sort, featureName })
}
return rows.sort((a, b) => a.sort - b.sort)
}

34
src/utils/wxMiniAuth.js Normal file
View File

@@ -0,0 +1,34 @@
import { postUserWxMiniAuth } from '@/api/user'
import { saveAuthSession } from '@/utils/session'
/**
* 微信小程序:`uni.login` → `/user/wxMiniAuth` → 写入 token
* @param {{ silent?: boolean }} [opts] silent=true不触发全局 loading、不弹业务/网络失败 Toast适合 App 启动静默登录)
* @returns {Promise<boolean>} 是否登录成功
*/
export async function tryWxMiniProgramAuth(opts = {}) {
const silent = opts.silent === true
const reqExtra = silent
? { skipLoading: true, skipBizToast: true }
: undefined
const loginRes = await new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: resolve,
fail: reject,
})
})
if (!loginRes?.code) {
if (!silent)
uni.showToast({ title: '未获取到微信登录凭证', icon: 'none' })
return false
}
const res = await postUserWxMiniAuth({ code: loginRes.code }, reqExtra)
if (res && res.code === 200 && res.data) {
saveAuthSession(res.data)
return true
}
return false
}