feat(frontend): 为前端添加完整移动端响应式适配
- 新增响应式工具函数与全局移动端样式,统一适配≤768px屏幕 - 添加移动端底部导航组件,替代桌面端侧边栏菜单 - 为经销商、客户、报备列表页新增移动端卡片视图替换表格布局 - 调整所有页面的表单、弹窗与布局适配移动端尺寸 - 优化移动端viewport配置,适配全面屏安全区域 - 修复密码哈希工具,在非安全上下文下回退使用js-sha256库 - 更新依赖包,新增@vueuse/core与js-sha256
This commit is contained in:
1 parent
4c6970c32d
commit
fd89c31640
16 files changed
+613
-62
No files matched your search
@@ -1,39 +1,44 @@
|
||||
/**
|
||||
* 密码加密工具
|
||||
* 使用 Web Crypto API 进行 SHA-256 哈希
|
||||
* 密码加密工具(SHA-256 → 小写 hex)
|
||||
*
|
||||
* 安全上下文(HTTPS 或 localhost)下使用原生 Web Crypto API;
|
||||
* 非安全上下文(HTTP + 局域网/IP 访问,此时 crypto.subtle 为 undefined)
|
||||
* 下回退到纯 JS 实现 js-sha256,保证产物一致,登录不再卡死。
|
||||
* 两条路径对同一字符串产出的 SHA-256 小写 hex 完全相同。
|
||||
*/
|
||||
import { sha256 } from 'js-sha256'
|
||||
|
||||
/**
|
||||
* 将字符串转换为 ArrayBuffer
|
||||
*/
|
||||
function stringToArrayBuffer(str: string): ArrayBuffer {
|
||||
const encoder = new TextEncoder()
|
||||
return encoder.encode(str).buffer
|
||||
/** 当前环境是否可用原生 Web Crypto(即处于安全上下文) */
|
||||
function hasSubtleCrypto(): boolean {
|
||||
return typeof crypto !== 'undefined' && typeof crypto.subtle?.digest === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 ArrayBuffer 转换为十六进制字符串
|
||||
*/
|
||||
function arrayBufferToHex(buffer: ArrayBuffer): string {
|
||||
const bytes = new Uint8Array(buffer)
|
||||
return Array.from(bytes)
|
||||
.map(b => b.toString(16).padStart(2, '0'))
|
||||
/** 原生 Web Crypto SHA-256 → 小写 hex */
|
||||
async function subtleSha256Hex(input: string): Promise<string> {
|
||||
const data = new TextEncoder().encode(input)
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
||||
return Array.from(new Uint8Array(hashBuffer))
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('')
|
||||
}
|
||||
|
||||
/** 统一入口:优先原生,回退纯 JS */
|
||||
async function sha256Hex(input: string): Promise<string> {
|
||||
if (hasSubtleCrypto()) {
|
||||
return subtleSha256Hex(input)
|
||||
}
|
||||
return sha256(input)
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 SHA-256 算法哈希密码
|
||||
* @param password 明文密码
|
||||
* @returns 哈希后的十六进制字符串
|
||||
* @returns 哈希后的十六进制字符串(小写)
|
||||
*/
|
||||
export async function hashPassword(password: string): Promise<string> {
|
||||
if (!password) return ''
|
||||
|
||||
try {
|
||||
// 使用 Web Crypto API 进行 SHA-256 哈希
|
||||
const data = stringToArrayBuffer(password)
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
||||
return arrayBufferToHex(hashBuffer)
|
||||
return await sha256Hex(password)
|
||||
} catch (error) {
|
||||
console.error('密码哈希失败:', error)
|
||||
throw new Error('密码加密失败')
|
||||
@@ -44,16 +49,12 @@ export async function hashPassword(password: string): Promise<string> {
|
||||
* 简单的加盐哈希(可选,用于增强安全性)
|
||||
* @param password 明文密码
|
||||
* @param salt 盐值
|
||||
* @returns 哈希后的十六进制字符串
|
||||
* @returns 哈希后的十六进制字符串(小写)
|
||||
*/
|
||||
export async function hashPasswordWithSalt(password: string, salt: string): Promise<string> {
|
||||
if (!password) return ''
|
||||
|
||||
try {
|
||||
const saltedPassword = password + salt
|
||||
const data = stringToArrayBuffer(saltedPassword)
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
||||
return arrayBufferToHex(hashBuffer)
|
||||
return await sha256Hex(password + salt)
|
||||
} catch (error) {
|
||||
console.error('密码哈希失败:', error)
|
||||
throw new Error('密码加密失败')
|
||||
|
||||
Reference in new issue
Block a user