Commit e90f4e4f by chunhong.mu

Merge branch 'feature/qqqf-admin' into dev

parents fc794e28 ee10fbb7
Showing with 1934 additions and 664 deletions
export default { export default {
extends: ['@commitlint/config-conventional'], extends: ['@commitlint/config-conventional'],
rules: { rules: {
'scope-enum': [2, 'always', ["root", "*", "@common/sdk", "@common/utils", "@common/vue-kit", "official-site-web", "qqqf-mp"]], 'scope-enum': [2, 'always', ["root", "*", "@common/sdk", "@common/utils", "@common/vue-kit", "official-site-web", "qqqf-admin", "qqqf-mp"]],
'scope-empty': [2, 'never'], 'scope-empty': [2, 'never'],
}, },
} }
...@@ -2,10 +2,19 @@ ...@@ -2,10 +2,19 @@
"name": "@common/sdk", "name": "@common/sdk",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"exports": {
".": "./src/index.ts",
"./mini-program": "./src/mini-program/index.ts",
"./services/login-service": "./src/services/login-service.ts",
"./services/verify-service": "./src/services/verify-service.ts"
},
"main": "src/index.ts", "main": "src/index.ts",
"dependencies": { "dependencies": {
"axios": "^0.27.2", "axios": "^0.27.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"uniplat-sdk": "^0.1.734-private" "uniplat-sdk": "^0.1.734-private"
},
"devDependencies": {
"@types/lodash": "^4.17.24"
} }
} }
// HTTP 适配器
export { uniAdapter } from "./uni-adapter"
export { webAdapter } from "./web-adapter"
...@@ -65,7 +65,7 @@ function transformError( ...@@ -65,7 +65,7 @@ function transformError(
), ),
) )
} else { } else {
reject(new AxiosError("Network Error", null, config, "")) reject(new AxiosError("Network Error", undefined, config, ""))
} }
} }
...@@ -86,7 +86,7 @@ export function uniAdapter(config: AxiosRequestConfig): AxiosPromise { ...@@ -86,7 +86,7 @@ export function uniAdapter(config: AxiosRequestConfig): AxiosPromise {
), ),
} as UniApp.RequestOptions } as UniApp.RequestOptions
const uniHeader: Record<string, string> = {} const uniHeader: Record<string, string> = {}
forEach(config.headers, (val, key) => { forEach(config.headers, (val: any, key: string) => {
const _header = key.toLowerCase() const _header = key.toLowerCase()
if ( if (
(typeof requestData === "undefined" && (typeof requestData === "undefined" &&
...@@ -94,7 +94,7 @@ export function uniAdapter(config: AxiosRequestConfig): AxiosPromise { ...@@ -94,7 +94,7 @@ export function uniAdapter(config: AxiosRequestConfig): AxiosPromise {
_header === "referer" _header === "referer"
) { ) {
} else { } else {
uniHeader[key] = val uniHeader[key] = String(val)
} }
}) })
uniConfig.header = uniHeader uniConfig.header = uniHeader
......
import type { AxiosPromise, AxiosRequestConfig, AxiosResponse } from "axios"
import { AxiosError } from "axios"
// @ts-ignore
import buildFullPath from "axios/lib/core/buildFullPath"
// @ts-ignore
import settle from "axios/lib/core/settle"
// @ts-ignore
import buildURL from "axios/lib/helpers/buildURL"
/**
* Web 平台 Axios 适配器
* 用于 Web 项目替代 uniAdapter
*/
export function webAdapter(config: AxiosRequestConfig): AxiosPromise {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
const { method = "GET", data, headers, timeout } = config
const fullPath = buildURL(
buildFullPath(config.baseURL, config.url),
config.params,
config.paramsSerializer,
)
xhr.open(method, fullPath, true)
xhr.timeout = timeout || 10000
xhr.responseType = config.responseType as XMLHttpRequestResponseType || "json"
// 设置请求头
if (headers) {
Object.entries(headers).forEach(([key, value]) => {
if (value !== undefined) {
xhr.setRequestHeader(key, String(value))
}
})
}
xhr.onload = () => {
const responseHeaders: Record<string, string> = {}
xhr.getAllResponseHeaders().split("\r\n").forEach((line) => {
const [key, ...rest] = line.split(": ")
if (key) {
responseHeaders[key] = rest.join(": ")
}
})
const response: AxiosResponse = {
data: xhr.response,
status: xhr.status,
statusText: xhr.statusText,
headers: responseHeaders as any,
config,
request: xhr,
}
settle(resolve, reject, response)
}
xhr.onerror = () => {
reject(new AxiosError("Network Error", undefined, config, xhr))
}
xhr.ontimeout = () => {
reject(new AxiosError(`timeout of ${timeout}ms exceeded`, "ECONNABORTED", config, xhr))
}
xhr.send(data)
})
}
/**
* 认证处理器接口
* 用于解耦 HTTP 请求层与登录服务层之间的依赖
*/
export interface AuthHandlers {
clearLoginMsg: () => void
logout: (jump?: boolean, loginUrl?: string) => void
afterSdkLogin: () => Promise<any>
getDeviceInfoWidthCache: () => void
}
let handlers: AuthHandlers | null = null
/**
* 注册认证处理器
*/
export function registerAuthHandlers(h: AuthHandlers) {
handlers = h
}
/**
* 获取已注册的认证处理器
*/
export function getAuthHandlers(): AuthHandlers | null {
return handlers
}
...@@ -17,7 +17,7 @@ export function buildImage( ...@@ -17,7 +17,7 @@ export function buildImage(
w = 0 w = 0
h = 0 h = 0
} }
const imageConfig = sdk.global.imageConfig const imageConfig = (sdk.global as any).imageConfig
if (imageConfig) { if (imageConfig) {
const { domain, protocol } = imageConfig const { domain, protocol } = imageConfig
const width = w !== undefined ? w : imageConfig.defaultWidth const width = w !== undefined ? w : imageConfig.defaultWidth
...@@ -39,7 +39,7 @@ export function buildFilePath( ...@@ -39,7 +39,7 @@ export function buildFilePath(
notForceDownload?: boolean, notForceDownload?: boolean,
): string { ): string {
if (!url) return "" if (!url) return ""
const fileConfig = sdk.global.fileConfig const fileConfig = (sdk.global as any).fileConfig
if (fileConfig && !notForceDownload) { if (fileConfig && !notForceDownload) {
const { domain, protocol } = fileConfig const { domain, protocol } = fileConfig
return `${protocol}://${domain}/download/${url}` return `${protocol}://${domain}/download/${url}`
......
// 图片/文件 URL 构建
export { buildFilePath, buildImage } from "./image-builder"
// SDK 核心
export {
ClientId,
Environment,
getAuthHandlers,
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SERVICE,
PASSPORT_SUB_PROJECT,
registerAuthHandlers,
Sdk,
wxDistributerUrlConfig,
} from "./sdk"
export type {
AuthHandlers,
SdkConfig,
SdkInitOptions,
} from "./sdk"
// Token 管理
export { decodeToken, TokenManager } from "./token-manager"
// 监控
export { Product, webMonitor } from "./web-monitor"
export type { MonitorOption } from "./web-monitor"
import type {
metaRow,
SdkListRowPredict,
SdkListRowPredictObject,
} from "uniplat-sdk"
import type { AxiosAdapter } from "uniplat-sdk/build/main/helpers/axios"
import {
decodeJwt,
UniplatSdk,
UniplatSdkExtender,
} from "uniplat-sdk"
import { Tree } from "uniplat-sdk/build/main/model/tree/tree"
import { buildFilePath, buildImage } from "./image-builder"
// ==================== 类型定义 ====================
export interface SdkConfig {
uniplatApi: string
rootEntrance: string
logEnv: string
clientId: string
domainService: {
subProjectName: string
serviceName: string
}
}
export interface SdkInitOptions {
baseUrl: string
sse?: boolean
axiosTimeout?: number
refreshInterval?: number
}
export interface AuthHandlers {
clearLoginMsg: () => void
logout: (jump?: boolean, loginUrl?: string) => void
afterSdkLogin: () => Promise<any>
getDeviceInfoWidthCache: () => void
}
// ==================== 常量定义 ====================
/** 子项目名称 */
export const PASSPORT_SUB_PROJECT = "uniplat_base"
/** 匿名服务名称 */
export const PASSPORT_ANONYMOUS_SERVICE = {
SystemUser: "anonymous/system.user",
SystemAuth: "anonymous/system.auth",
SystemWechat: "anonymous/system.wechat",
} as const
/** 认证服务名称 */
export const PASSPORT_SERVICE = {
SystemUser: "system.user",
SystemAuth: "system.auth",
SystemWechat: "system.wechat",
} as const
// ==================== 环境/客户端枚举 ====================
export enum Environment {
Dev = "dev",
Test = "test",
Pro = "pro",
Stage = "stage",
}
export enum ClientId {
None = "",
QqxbApp = "qqxb-hrm-app-ios",
QqtxzMp = "qqxb_mini_app",
FlbMp = "qqxb_flb_mini_app",
WebLogin = "teamix-personal-center-web-pc",
RenCaiKuaiDiMp = "welfare_bean_wechat_mini_app",
YuZhiPinMp = "chongqing_job_mini_app",
RenCaiKuaiDiH5 = "welfare_bean_qqxb_h5",
RenCaiKuaiDiPc = "welfare_bean_agent_pc",
Hrs100 = "hrs100-front-web-pc",
QqxbOfficial = "qqxb-official-web",
FastServiceWeb = "teamix-fast-service-web",
FastServiceMerchant = "teamix-fast-service-merchant",
Hrs100WechatMiniApp = "hrs100_wechat_mini_app",
Donghu = "donghu-web-pc",
}
// ==================== URL 配置 ====================
const qqxbPassportConfig = new Map<Environment, string>([
[
Environment.Dev,
"http://191env1.report.qinqinxiaobao-passport.qqxb.jinsehuaqin.com:8800",
],
[
Environment.Test,
"http://191env1.report.qinqinxiaobao-passport.qqxb.jinsehuaqin.com:8800",
],
[Environment.Pro, "https://passport.qinqinxiaobao.com"],
[Environment.Stage, "https://pre-passport.qinqinxiaobao.com"],
])
export const wxDistributerUrlConfig = new Map<Environment, string>([
[Environment.Dev, "http://wechat.test.teammix.qqxb.cn"],
[Environment.Test, "https://pre-wx-distributer.teammix.com"],
[Environment.Pro, "https://wx-distributer.teammix.com"],
[Environment.Stage, "https://pre-wx-distributer.teammix.com"],
])
// ==================== AuthHandlers 管理 ====================
let authHandlers: AuthHandlers | null = null
export function registerAuthHandlers(h: AuthHandlers) {
authHandlers = h
}
export function getAuthHandlers(): AuthHandlers | null {
return authHandlers
}
// ==================== Sdk 核心类 ====================
export class Sdk {
private uniplatSdk!: UniplatSdk
private readonly handler = new UniplatSdkExtender()
private token!: string
public orgId!: number
private client = ClientId.None
private passportUrl = ""
private wxDistributerUrl = ""
constructor(config?: SdkConfig, adapter?: AxiosAdapter) {
if (config) {
this.init(config, adapter)
}
}
public init(config: SdkConfig, adapter?: AxiosAdapter) {
const baseUrl = config.uniplatApi
this.uniplatSdk = new UniplatSdk({ sse: false })
this.uniplatSdk.global.baseUrl = baseUrl
this.uniplatSdk.connect({
baseUrl,
axiosAdapter: adapter,
axiosTimeout: 10e3,
refreshInterval: 10 * 60 * 1000,
})
this.uniplatSdk.getAxios().defaults.timeout = 10e3
this.uniplatSdk.global.rootEntrance = config.rootEntrance
this.client = (config.clientId as ClientId) || ClientId.None
const envir = (config.logEnv as Environment) || Environment.Dev
this.passportUrl =
qqxbPassportConfig.get(envir) ||
qqxbPassportConfig.get(Environment.Dev)!
this.wxDistributerUrl =
wxDistributerUrlConfig.get(envir) ||
wxDistributerUrlConfig.get(Environment.Dev)!
}
public setupEventHandlers(handlers: {
onTokenExpiring: () => void
onUniversalError: (error: any) => void
}) {
this.uniplatSdk.events.addUniversalErrorResponseCallback(
handlers.onUniversalError,
)
this.uniplatSdk.events.addTokenExpiring(handlers.onTokenExpiring)
}
public get core() {
return this.uniplatSdk
}
public get storage() {
return this.uniplatSdk?.global.storage || localStorage
}
public get clientId() {
return this.client
}
public get passport() {
return this.passportUrl
}
public get wxDistributer() {
return this.wxDistributerUrl
}
public buildPassport4Logout(redirect?: string) {
if (redirect) {
return `${this.passportUrl}?redirectUrl=${redirect}&logout=1`
}
return `${this.passportUrl}?logout=1`
}
public forgetPassword() {
return `${this.passportUrl}/forget`
}
public register() {
return `${this.passportUrl}/register?redirectUrl=${encodeURIComponent(
window.location.href,
)}`
}
public domainServiceGet<ParamsType, ReturnType>(
apiName: string,
params?: ParamsType,
isAnonymous?: boolean,
subProjectName?: string,
serviceName?: string,
config?: SdkConfig,
) {
return this.uniplatSdk
.domainService(
subProjectName || config?.domainService.subProjectName || "",
(isAnonymous ? "anonymous/" : "") +
(serviceName || config?.domainService.serviceName || ""),
apiName,
)
.request<ParamsType, unknown, ReturnType>("get", {
params,
})
}
public domainServicePost<ParamsType, DataType, ReturnType>(
apiName: string,
params?: {
data?: DataType
params?: ParamsType
},
isAnonymous?: boolean,
subProjectName?: string,
serviceName?: string,
config?: SdkConfig,
) {
return this.uniplatSdk
.domainService(
subProjectName || config?.domainService.subProjectName || "",
(isAnonymous ? "anonymous/" : "") +
(serviceName || config?.domainService.serviceName || ""),
apiName,
)
.request<ParamsType, DataType, ReturnType>("post", params)
}
public buildRows<T>(
rows: metaRow[],
predicts: SdkListRowPredict[] | SdkListRowPredictObject,
) {
return this.handler.buildRows<T>(rows, predicts)
}
public buildRow<T>(
item: metaRow,
predicts: SdkListRowPredict[] | SdkListRowPredictObject,
) {
return this.handler.buildRow<T>(item, predicts)
}
public buildActionParameter(parameter: { [key: string]: any }) {
return this.handler.buildActionParameter(parameter)
}
public buildImageUrl(url?: string, w?: number, h?: number, view?: boolean) {
return buildImage(this.uniplatSdk, url, w, h, view)
}
public buildFileUrl(url: string, notForceDownload?: boolean) {
return buildFilePath(this.uniplatSdk, url, notForceDownload)
}
public tree(modelName: string) {
return new Tree(modelName)
}
public decodeToken<T>(token: string) {
return decodeJwt<T>(token)
}
public getAxios() {
return this.uniplatSdk.getAxios()
}
}
import type { AxiosAdapter } from "axios" import type { AxiosAdapter } from "axios"
import type { Index } from "uniplat-sdk" import type { Index } from "uniplat-sdk"
import { decodeJwt, UniplatSdk } from "uniplat-sdk" import { decodeJwt, UniplatSdk } from "uniplat-sdk"
import { UICore } from "./ui-core"
/** /**
* 登录 API 名称枚举 * 登录 API 名称枚举
...@@ -13,21 +12,34 @@ export enum LoginApiName { ...@@ -13,21 +12,34 @@ export enum LoginApiName {
} }
/** /**
* Passport Token 控制 * Token 管理
* 负责 Token 的保存、验证、获取用户信息等 * 负责 Token 的保存、验证、获取用户信息等
*/ */
export class PassportTokenController { export class TokenManager {
private static readonly key = "JWT_TOKEN" private static readonly key = "JWT_TOKEN"
private static baseUrl = "" private static baseUrl = ""
private static ssr = false private static ssr = false
private static storageInstance: Storage | null = null
public static setupBaseUrl(baseUrl: string) { public static setupBaseUrl(baseUrl: string) {
this.baseUrl = baseUrl this.baseUrl = baseUrl
return this return this
} }
/**
* 设置自定义存储实例
*/
public static setupStorage(storage: Storage) {
this.storageInstance = storage
return this
}
private static get storage() {
return this.storageInstance || localStorage
}
public static clearToken() { public static clearToken() {
UICore.storage.removeItem(this.key) this.storage.removeItem(this.key)
} }
public static useSsrMode() { public static useSsrMode() {
...@@ -57,13 +69,17 @@ export class PassportTokenController { ...@@ -57,13 +69,17 @@ export class PassportTokenController {
.then((r) => { .then((r) => {
const o = r as Index.loginByPassportRequestResult const o = r as Index.loginByPassportRequestResult
if (o.jwt) { if (o.jwt) {
this.ssr && (UICore.core.global.ssr = true) if (this.ssr) {
UICore.storage.setItem(this.key, o.jwt) ;(sdk.global as any).ssr = true
}
this.storage.setItem(this.key, o.jwt)
} }
}) })
} else { } else {
this.ssr && (UICore.core.global.ssr = true) if (this.ssr) {
UICore.storage.setItem(this.key, token) // SSR mode requires sdk.global to be set
}
this.storage.setItem(this.key, token)
return Promise.resolve() return Promise.resolve()
} }
} }
...@@ -81,13 +97,13 @@ export class PassportTokenController { ...@@ -81,13 +97,13 @@ export class PassportTokenController {
public static hasToken() { public static hasToken() {
const cache = const cache =
UICore.storage.getItem(this.key) || this.storage.getItem(this.key) ||
(UICore.core && UICore.core.global.jwtToken) (UniplatSdk.prototype && (window as any).jwtToken)
if (cache) { if (cache) {
if (this.isTokenValid(cache)) { if (this.isTokenValid(cache)) {
return cache return cache
} }
UICore.storage.removeItem(this.key) this.storage.removeItem(this.key)
return null return null
} }
return cache return cache
...@@ -95,8 +111,7 @@ export class PassportTokenController { ...@@ -95,8 +111,7 @@ export class PassportTokenController {
public static checkTokenExit() { public static checkTokenExit() {
const cache = const cache =
UICore.storage.getItem(this.key) || this.storage.getItem(this.key) || ((window as any).jwtToken)
(UICore.core && UICore.core.global.jwtToken)
return cache return cache
} }
......
...@@ -30,7 +30,7 @@ enum ProductTable { ...@@ -30,7 +30,7 @@ enum ProductTable {
Error = "error", Error = "error",
} }
export interface SdkMonitorOption { export interface MonitorOption {
userAgent?: boolean userAgent?: boolean
envir: string envir: string
product: Product product: Product
...@@ -106,7 +106,7 @@ class WebMonitor { ...@@ -106,7 +106,7 @@ class WebMonitor {
public useSdk( public useSdk(
sdk: UniplatSdk, sdk: UniplatSdk,
options: SdkMonitorOption, options: MonitorOption,
adapter?: AxiosAdapter, adapter?: AxiosAdapter,
) { ) {
this.envir = options.envir this.envir = options.envir
...@@ -173,4 +173,4 @@ class WebMonitor { ...@@ -173,4 +173,4 @@ class WebMonitor {
} }
} }
export const monitor = new WebMonitor() export const webMonitor = new WebMonitor()
import type { SdkCore } from "./sdk-core"
/**
* HTTP 请求服务
* 提供静态 get/post 方法,用于简单的 HTTP 请求
*/
export default class HttpRequest {
protected sdk!: SdkCore
public static get<T>(url: string, params?: any) {
throw new Error("sdk instance not set")
}
public static post<T>(url: string, data?: any) {
throw new Error("sdk instance not set")
}
}
/**
* 增强版 HttpRequest,支持传入 sdk 实例
*/
export class HttpRequestWithSdk {
constructor(protected sdk: SdkCore) {}
public get<T>(url: string, params?: any) {
return this.sdk.getAxios().get<{}, T>(url, { params })
}
public post<T>(url: string, data?: any) {
return this.sdk.getAxios().post<{}, T>(url, data)
}
}
// 平台条件执行器 // HTTP 适配器
export { ActionInvoker } from "./action-invoker" export { uniAdapter } from "./adapters/uni-adapter"
// 认证处理器
export { getAuthHandlers, registerAuthHandlers } from "./auth-handlers"
export type { AuthHandlers } from "./auth-handlers"
// 文件操作(上传/下载/预览)
export {
AppFileType,
chooseImage,
downloadFile,
previewDocument,
} from "./file-operations"
export type { UploadData } from "./file-operations"
// HTTP 请求服务 export { webAdapter } from "./adapters/web-adapter"
export { HttpRequestWithSdk } from "./http-request"
export { default as HttpRequest } from "./http-request"
// 图片/文件 URL 构建 // 图片/文件 URL 构建
export { buildFilePath, buildImage } from "./image-builder" export { buildFilePath, buildImage } from "./core/image-builder"
// 登录服务 // SDK 核心(合并了类型、常量、AuthHandlers)
export { loginService } from "./login-service"
export type { LoginRegisterResult, RegisterChannel } from "./login-service"
// 小程序工具
export {
MiniProgramVersion,
navigateBackMiniProgram,
navigateToMiniProgram,
} from "./mini-program"
export type { MiniProgramNavConfig } from "./mini-program"
// 监控
export { monitor, Product } from "./monitor"
export type { SdkMonitorOption } from "./monitor"
// Passport 公共常量
export { export {
ClientId,
Environment,
getAuthHandlers,
PASSPORT_ANONYMOUS_SERVICE, PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SERVICE, PASSPORT_SERVICE,
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
} from "./passport-constants" registerAuthHandlers,
Sdk,
wxDistributerUrlConfig,
} from "./core/sdk"
// SDK 控制器 export type {
export { SdkController } from "./sdk-controller" AuthHandlers,
SdkConfig,
SdkInitOptions,
} from "./core/sdk"
// SDK 核心 export { Sdk as SdkCore } from "./core/sdk"
export { SdkCore } from "./sdk-core"
export type { SdkConfig, SdkInitOptions } from "./sdk-types"
// 分享
export { createShareMixin, finalShareData, setShareData } from "./share"
// Token 管理 // Token 管理
export { decodeToken, PassportTokenController } from "./token-manager" export { decodeToken, TokenManager } from "./core/token-manager"
// 核心配置 // 向后兼容别名
export { ClientId, Environment, UICore, wxDistributerUrlConfig } from "./ui-core" export { TokenManager as PassportTokenController } from "./core/token-manager"
// HTTP 适配器 // 监控
export { uniAdapter } from "./uni-adapter" export { Product, webMonitor } from "./core/web-monitor"
// 小程序版本更新
export { updateManager } from "./update-manager" export type { MonitorOption } from "./core/web-monitor"
// 小程序模块
export * from "./mini-program"
// 验证码服务 // 服务工厂函数
export { verifyService } from "./verify-service" export { createLoginService, LoginApiName } from "./services/login-service"
export type { VerifyImageResult } from "./verify-service" export type { LoginRegisterResult, RegisterChannel } from "./services/login-service"
// 微信登录服务 export { createVerifyService, VerifyApiName } from "./services/verify-service"
export { wechatLoginService } from "./wechat-login-service"
export type { RegisterChannel, WechatLoginResult } from "./wechat-login-service" export type { VerifyImageResult } from "./services/verify-service"
...@@ -88,7 +88,7 @@ export function previewDocument(path: string): Promise<void> { ...@@ -88,7 +88,7 @@ export function previewDocument(path: string): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
if (isVideo) { if (isVideo) {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
wx.previewMedia({ ;(globalThis as any).wx?.previewMedia({
sources: urls.map(e => ({ url: e, type: "video" })), sources: urls.map(e => ({ url: e, type: "video" })),
success: () => resolve(), success: () => resolve(),
fail: () => reject(), fail: () => reject(),
......
// 小程序专属导出(仅小程序项目使用)
// 条件执行器
export { ActionInvoker } from "./action-invoker"
// 文件操作(上传/下载/预览)
export {
AppFileType,
chooseImage,
downloadFile,
previewDocument,
} from "./file-operations"
export type { UploadData } from "./file-operations"
// 小程序工具
export {
MiniProgramVersion,
navigateBackMiniProgram,
navigateToMiniProgram,
} from "./mini-program"
export type { MiniProgramNavConfig } from "./mini-program"
// 小程序版本更新
export { updateManager } from "./update-manager"
// 微信登录服务
export { WechatLoginService } from "./wechat-login-service"
export type { RegisterChannel, WechatLoginResult } from "./wechat-login-service"
...@@ -5,14 +5,16 @@ import { ActionInvoker } from "./action-invoker" ...@@ -5,14 +5,16 @@ import { ActionInvoker } from "./action-invoker"
*/ */
export function updateManager(contentText: string) { export function updateManager(contentText: string) {
ActionInvoker.executeMp(() => { ActionInvoker.executeMp(() => {
const wx = (globalThis as any).wx
if (!wx) return
const updateManager = wx.getUpdateManager() const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate((res) => { updateManager.onCheckForUpdate((res: any) => {
if (res.hasUpdate) { if (res.hasUpdate) {
updateManager.onUpdateReady(() => { updateManager.onUpdateReady(() => {
wx.showModal({ wx.showModal({
title: "更新提示", title: "更新提示",
content: contentText || "", content: contentText || "",
success(res) { success(res: any) {
if (res.confirm) { if (res.confirm) {
updateManager.applyUpdate() updateManager.applyUpdate()
} }
......
import {
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SUB_PROJECT,
} from "./passport-constants"
/** /**
* 微信登录服务 * 微信登录服务
* 提供微信小程序绑定手机号登录等功能 * 提供微信小程序绑定手机号登录等功能
*/ */
import { UICore } from "./ui-core" import type { Sdk } from "../core/sdk"
import {
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SUB_PROJECT,
} from "../core/sdk"
export enum WechatLoginApiName { export enum WechatLoginApiName {
BindPhone = "bind_phone", BindPhone = "bind_phone",
...@@ -28,6 +28,8 @@ export interface WechatLoginResult { ...@@ -28,6 +28,8 @@ export interface WechatLoginResult {
} }
export class WechatLoginService { export class WechatLoginService {
constructor(private sdk: Sdk) {}
/** /**
* 微信小程序绑定手机号登录 * 微信小程序绑定手机号登录
*/ */
...@@ -38,7 +40,7 @@ export class WechatLoginService { ...@@ -38,7 +40,7 @@ export class WechatLoginService {
iv: string, iv: string,
registerChannel: RegisterChannel = {}, registerChannel: RegisterChannel = {},
) { ) {
return UICore.core return this.sdk.core
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_ANONYMOUS_SERVICE.SystemWechat, PASSPORT_ANONYMOUS_SERVICE.SystemWechat,
...@@ -52,7 +54,7 @@ export class WechatLoginService { ...@@ -52,7 +54,7 @@ export class WechatLoginService {
data: { data: {
appid, appid,
code, code,
client_id: UICore.clientId, client_id: this.sdk.clientId,
encryptedData, encryptedData,
iv, iv,
...registerChannel, ...registerChannel,
...@@ -60,5 +62,3 @@ export class WechatLoginService { ...@@ -60,5 +62,3 @@ export class WechatLoginService {
}) })
} }
} }
export const wechatLoginService = new WechatLoginService()
/**
* Passport 公共常量
* 定义子项目名称和服务名称
*/
/** 子项目名称 */
export const PASSPORT_SUB_PROJECT = "uniplat_base"
/** 匿名服务名称 */
export const PASSPORT_ANONYMOUS_SERVICE = {
SystemUser: "anonymous/system.user",
SystemAuth: "anonymous/system.auth",
SystemWechat: "anonymous/system.wechat",
} as const
/** 认证服务名称 */
export const PASSPORT_SERVICE = {
SystemUser: "system.user",
SystemAuth: "system.auth",
SystemWechat: "system.wechat",
} as const
import type { UniplatSdk } from "uniplat-sdk"
/**
* SDK 控制器
* 负责构建图片路径、文件路径等
*/
export class SdkController {
public static buildImage(
sdk: UniplatSdk,
url: string,
w?: number,
h?: number,
view?: boolean,
) {
if (/^http/.test(url)) {
// 将错误的"//fs"转换为"/fs"
return url.replace(/\/\/fs/, "/fs")
}
// 移除前面可能存在的"/"
const t = url.replace(/^\/(.*)/, "$1")
return (
sdk.global.baseUrl +
sdk.mediaController.buildThumbnail(t, w, h, view)
)
}
public static buildFilePath(
sdk: UniplatSdk,
url: string,
notForceDownload?: boolean,
) {
if (/^http/.test(url)) {
return url
}
if (url.startsWith("/")) {
return sdk.global.baseUrl + url.replace("/", "")
}
return (
sdk.global.baseUrl +
url +
(notForceDownload
? `?parameters=${encodeURIComponent(
JSON.stringify({
forceDownload: false,
}),
)}`
: "")
)
}
}
import type {
metaRow,
SdkListRowPredict,
SdkListRowPredictObject,
} from "uniplat-sdk"
import type { AxiosAdapter } from "uniplat-sdk/build/main/helpers/axios"
import type { SdkConfig } from "./sdk-types"
import {
decodeJwt,
UniplatSdk,
UniplatSdkExtender,
} from "uniplat-sdk"
import { Tree } from "uniplat-sdk/build/main/model/tree/tree"
import { buildFilePath, buildImage } from "./image-builder"
import { uniAdapter } from "./uni-adapter"
export class SdkCore {
private uniplatSdk!: UniplatSdk
private readonly handler = new UniplatSdkExtender()
private token!: string
public orgId!: number
constructor(config?: SdkConfig) {
if (config) {
this.init(config)
}
}
public init(config: SdkConfig) {
const baseUrl = config.uniplatApi
this.uniplatSdk = new UniplatSdk({ sse: false })
this.uniplatSdk.global.baseUrl = baseUrl
let adapter: AxiosAdapter | undefined
// #ifdef MP
adapter = uniAdapter
// #endif
this.uniplatSdk.connect({
baseUrl,
axiosAdapter: adapter,
axiosTimeout: 10e3,
refreshInterval: 10 * 60 * 1000,
})
// #ifndef MP
this.uniplatSdk.getAxios().defaults.timeout = 10e3
// #endif
this.uniplatSdk.global.rootEntrance = config.rootEntrance
}
public setupEventHandlers(handlers: {
onTokenExpiring: () => void
onUniversalError: (error: any) => void
}) {
this.uniplatSdk.events.addUniversalErrorResponseCallback(handlers.onUniversalError)
this.uniplatSdk.events.addTokenExpiring(handlers.onTokenExpiring)
}
public get core() {
return this.uniplatSdk
}
public domainServiceGet<ParamsType, ReturnType>(
apiName: string,
params?: ParamsType,
isAnonymous?: boolean,
subProjectName?: string,
serviceName?: string,
config?: SdkConfig,
) {
return this.uniplatSdk
.domainService(
subProjectName || config?.domainService.subProjectName || "",
(isAnonymous ? "anonymous/" : "") +
(serviceName || config?.domainService.serviceName || ""),
apiName,
)
.request<ParamsType, unknown, ReturnType>("get", {
params,
})
}
public domainServicePost<ParamsType, DataType, ReturnType>(
apiName: string,
params?: {
data?: DataType
params?: ParamsType
},
isAnonymous?: boolean,
subProjectName?: string,
serviceName?: string,
config?: SdkConfig,
) {
return this.uniplatSdk
.domainService(
subProjectName || config?.domainService.subProjectName || "",
(isAnonymous ? "anonymous/" : "") +
(serviceName || config?.domainService.serviceName || ""),
apiName,
)
.request<ParamsType, DataType, ReturnType>("post", params)
}
public buildRows<T>(
rows: metaRow[],
predicts: SdkListRowPredict[] | SdkListRowPredictObject,
) {
return this.handler.buildRows<T>(rows, predicts)
}
public buildRow<T>(
item: metaRow,
predicts: SdkListRowPredict[] | SdkListRowPredictObject,
) {
return this.handler.buildRow<T>(item, predicts)
}
public buildActionParameter(parameter: { [key: string]: any }) {
return this.handler.buildActionParameter(parameter)
}
public buildImageUrl(url?: string, w?: number, h?: number, view?: boolean) {
return buildImage(this.uniplatSdk, url, w, h, view)
}
public buildFileUrl(url: string, notForceDownload?: boolean) {
return buildFilePath(this.uniplatSdk, url, notForceDownload)
}
public tree(modelName: string) {
return new Tree(modelName)
}
public decodeToken<T>(token: string) {
return decodeJwt<T>(token)
}
}
export interface SdkConfig {
uniplatApi: string
rootEntrance: string
logEnv: string
clientId: string
domainService: {
subProjectName: string
serviceName: string
}
}
export interface SdkInitOptions {
baseUrl: string
sse?: boolean
axiosTimeout?: number
refreshInterval?: number
}
// 服务工厂函数
export { createLoginService, LoginApiName } from "./login-service"
export type { LoginRegisterResult, RegisterChannel } from "./login-service"
export { createVerifyService, VerifyApiName } from "./verify-service"
export type { VerifyImageResult } from "./verify-service"
import {
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SERVICE,
PASSPORT_SUB_PROJECT,
} from "./passport-constants"
/** /**
* 登录服务 * 登录服务
* 提供密码登录、验证码登录等功能 * 提供密码登录、验证码登录等功能
*/ */
import { UICore } from "./ui-core" import type { UniplatSdk } from "uniplat-sdk"
import {
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SERVICE,
PASSPORT_SUB_PROJECT,
} from "../core/sdk"
export enum LoginApiName { export enum LoginApiName {
LoginWithPassword = "loginWithPassword", LoginWithPassword = "loginWithPassword",
...@@ -43,12 +43,28 @@ export interface RegisterChannel { ...@@ -43,12 +43,28 @@ export interface RegisterChannel {
[key: string]: any [key: string]: any
} }
export class LoginService { export function createLoginService(sdk: UniplatSdk, clientId: string) {
/**
* 移除 value 为 0、null、"" 的值
* 注册接口对一些值有要求,比如活动 id 要么不传要么>0 不能传""
*/
function buildNotNullProperty(o: Record<string, any>) {
const t = {} as Record<string, string | number | boolean>
for (const p in o) {
const v = o[p]
if (v || v === true || v === false) {
t[p] = v
}
}
return t
}
return {
/** /**
* 密码登录 * 密码登录
*/ */
public login(username: string, password: string) { login(username: string, password: string) {
return UICore.core return sdk
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_ANONYMOUS_SERVICE.SystemUser, PASSPORT_ANONYMOUS_SERVICE.SystemUser,
...@@ -57,14 +73,14 @@ export class LoginService { ...@@ -57,14 +73,14 @@ export class LoginService {
.post<LoginRegisterResult>({ .post<LoginRegisterResult>({
password, password,
username, username,
client_id: UICore.clientId, client_id: clientId,
}) })
} },
/** /**
* 验证码登录 * 验证码登录
*/ */
public verifyCodeLogin( verifyCodeLogin(
mobile: string, mobile: string,
verifycode: string, verifycode: string,
optional?: RegisterChannel, optional?: RegisterChannel,
...@@ -72,51 +88,35 @@ export class LoginService { ...@@ -72,51 +88,35 @@ export class LoginService {
const data: Record<string, any> = { const data: Record<string, any> = {
mobile, mobile,
verifycode, verifycode,
client_id: UICore.clientId, client_id: clientId,
} }
if (optional) { if (optional) {
Object.assign(data, this.buildNotNullProperty(optional)) Object.assign(data, buildNotNullProperty(optional))
} }
return UICore.core return sdk
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_ANONYMOUS_SERVICE.SystemUser, PASSPORT_ANONYMOUS_SERVICE.SystemUser,
LoginApiName.LoginWithVerifyCode, LoginApiName.LoginWithVerifyCode,
) )
.post<LoginRegisterResult>(data) .post<LoginRegisterResult>(data)
} },
/** /**
* 刷新登录 * 刷新登录
*/ */
public refreshLogin( refreshLogin(
optional?: RegisterChannel, optional?: RegisterChannel,
deviceInfo?: Record<string, string>, deviceInfo?: Record<string, string>,
) { ) {
const p = optional || {} const p = optional || {}
return UICore.core return sdk
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_SERVICE.SystemUser, PASSPORT_SERVICE.SystemUser,
LoginApiName.RefreshToken, LoginApiName.RefreshToken,
) )
.post(p, { client_id: UICore.clientId, ...deviceInfo }) .post(p, { client_id: clientId, ...deviceInfo })
} },
/**
* 移除 value 为 0、null、"" 的值
* 注册接口对一些值有要求,比如活动 id 要么不传要么>0 不能传""
*/
private buildNotNullProperty(o: Record<string, any>) {
const t = {} as Record<string, string | number | boolean>
for (const p in o) {
const v = o[p]
if (v || v === true || v === false) {
t[p] = v
}
}
return t
} }
} }
export const loginService = new LoginService()
import {
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SUB_PROJECT,
} from "./passport-constants"
/** /**
* 验证码服务 * 验证码服务
* 提供图形验证码生成、短信验证码发送等功能 * 提供图形验证码生成、短信验证码发送等功能
*/ */
import { UICore } from "./ui-core" import type { UniplatSdk } from "uniplat-sdk"
import {
PASSPORT_ANONYMOUS_SERVICE,
PASSPORT_SUB_PROJECT,
} from "../core/sdk"
export enum VerifyApiName { export enum VerifyApiName {
SendVerifyCode = "sendVerifyCode", SendVerifyCode = "sendVerifyCode",
...@@ -18,19 +18,24 @@ export interface VerifyImageResult { ...@@ -18,19 +18,24 @@ export interface VerifyImageResult {
seed: string seed: string
} }
export class VerifyService { export function createVerifyService(sdk: UniplatSdk, clientId: string) {
return {
/** /**
* 生成图形验证码 * 生成图形验证码
*/ */
public generateImage(): VerifyImageResult { generateImage(): VerifyImageResult {
return UICore.core.getVerifyImageAndSeed() const result = sdk.getVerifyImageAndSeed() as any
return {
img: result.img,
seed: String(result.seed),
} }
},
/** /**
* 发送短信验证码(需要图形验证码) * 发送短信验证码(需要图形验证码)
*/ */
public sendVerifyCode(mobile: string, seed: string, verifycode: string) { sendVerifyCode(mobile: string, seed: string, verifycode: string) {
return UICore.core return sdk
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_ANONYMOUS_SERVICE.SystemUser, PASSPORT_ANONYMOUS_SERVICE.SystemUser,
...@@ -41,13 +46,13 @@ export class VerifyService { ...@@ -41,13 +46,13 @@ export class VerifyService {
Record<string, unknown>, Record<string, unknown>,
void void
>("post", { data: { mobile, seed, verifycode } }) >("post", { data: { mobile, seed, verifycode } })
} },
/** /**
* 发送短信验证码(使用 token) * 发送短信验证码(使用 token)
*/ */
public sendVerifyCodeWithToken(mobile: string, token: string) { sendVerifyCodeWithToken(mobile: string, token: string) {
return UICore.core return sdk
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_ANONYMOUS_SERVICE.SystemUser, PASSPORT_ANONYMOUS_SERVICE.SystemUser,
...@@ -58,13 +63,13 @@ export class VerifyService { ...@@ -58,13 +63,13 @@ export class VerifyService {
Record<string, unknown>, Record<string, unknown>,
void void
>("post", { data: { mobile, token } }) >("post", { data: { mobile, token } })
} },
/** /**
* 验证手机号 * 验证手机号
*/ */
public verifyMobile(mobile: string, verifycode: string) { verifyMobile(mobile: string, verifycode: string) {
return UICore.core return sdk
.domainService( .domainService(
PASSPORT_SUB_PROJECT, PASSPORT_SUB_PROJECT,
PASSPORT_ANONYMOUS_SERVICE.SystemUser, PASSPORT_ANONYMOUS_SERVICE.SystemUser,
...@@ -75,9 +80,8 @@ export class VerifyService { ...@@ -75,9 +80,8 @@ export class VerifyService {
Record<string, unknown>, Record<string, unknown>,
{ check_result: boolean } { check_result: boolean }
>("post", { >("post", {
data: { mobile, verifycode, client_id: UICore.clientId }, data: { mobile, verifycode, client_id: clientId },
}) })
},
} }
} }
export const verifyService = new VerifyService()
import { last } from "lodash"
import { ref } from "vue"
const defaultShareData = {
title: "亲亲创客",
path: "/pages/home/index",
imageUrl: "",
}
export const finalShareData = ref<{
[key: string]: {
title: string
path: string
imageUrl: string
}
}>({})
/**
* 设置当前页面分享
*/
export function setShareData(shareData: {
title?: string
path?: string
imageUrl?: string
}) {
const p = last(getCurrentPages())
finalShareData.value = {
...finalShareData.value,
[p!.route]: {
...defaultShareData,
...shareData,
},
}
}
/**
* 创建全局分享 mixin,所有页面默认携带 shareAppMessage 配置
*/
export function createShareMixin() {
return {
onShareAppMessage() {
const p = last(getCurrentPages())
return finalShareData.value[p!.route] || defaultShareData
},
}
}
import type { AxiosAdapter } from "axios"
import type {
metaRow,
SdkListRowPredict,
SdkListRowPredictObject,
UniplatSdk,
} from "uniplat-sdk"
import { UniplatSdkExtender } from "uniplat-sdk"
/**
* 环境枚举
*/
export enum Environment {
Dev = "dev",
Test = "test",
Pro = "pro",
Stage = "stage",
}
/**
* 客户端 ID 枚举
*/
export enum ClientId {
None = "",
QqxbApp = "qqxb-hrm-app-ios",
QqtxzMp = "qqxb_mini_app",
FlbMp = "qqxb_flb_mini_app",
WebLogin = "teamix-personal-center-web-pc",
RenCaiKuaiDiMp = "welfare_bean_wechat_mini_app",
YuZhiPinMp = "chongqing_job_mini_app",
RenCaiKuaiDiH5 = "welfare_bean_qqxb_h5",
RenCaiKuaiDiPc = "welfare_bean_agent_pc",
Hrs100 = "hrs100-front-web-pc",
QqxbOfficial = "qqxb-official-web",
FastServiceWeb = "teamix-fast-service-web",
FastServiceMerchant = "teamix-fast-service-merchant",
Hrs100WechatMiniApp = "hrs100_wechat_mini_app",
Donghu = "donghu-web-pc",
}
/**
* Passport 配置
*/
const qqxbPassportConfig = new Map<Environment, string>([
[
Environment.Dev,
"http://191env1.report.qinqinxiaobao-passport.qqxb.jinsehuaqin.com:8800",
],
[
Environment.Test,
"http://191env1.report.qinqinxiaobao-passport.qqxb.jinsehuaqin.com:8800",
],
[Environment.Pro, "https://passport.qinqinxiaobao.com"],
[Environment.Stage, "https://pre-passport.qinqinxiaobao.com"],
])
/**
* 微信分销商 URL 配置
*/
export const wxDistributerUrlConfig = new Map<Environment, string>([
[Environment.Dev, "http://wechat.test.teammix.qqxb.cn"],
[Environment.Test, "https://pre-wx-distributer.teammix.com"],
[Environment.Pro, "https://wx-distributer.teammix.com"],
[Environment.Stage, "https://pre-wx-distributer.teammix.com"],
])
/**
* UI 核心配置类
* 负责 SDK 初始化配置、客户端 ID、Passport URL 等
*/
export class UICore {
private static sdk: UniplatSdk | null = null
private static adapter: AxiosAdapter | null = null
private static client = ClientId.None
private static passportUrl = ""
private static wxDistributerUrl = ""
private static readonly handler = new UniplatSdkExtender()
public static setupSdk(
sdk: UniplatSdk,
params?: {
client?: ClientId
envir?: Environment
config?: AxiosAdapter
},
) {
this.sdk = sdk
if (params) {
this.adapter = params.config as AxiosAdapter
this.client = params.client as ClientId
}
if (params?.envir) {
this.passportUrl = qqxbPassportConfig.get(params.envir) as string
this.wxDistributerUrl = wxDistributerUrlConfig.get(
params.envir,
) as string
}
if (!this.passportUrl) {
this.passportUrl = qqxbPassportConfig.get(Environment.Dev) as string
}
if (!this.wxDistributerUrl) {
this.wxDistributerUrl = wxDistributerUrlConfig.get(
Environment.Dev,
) as string
}
}
public static get core() {
return this.sdk as UniplatSdk
}
public static get storage() {
return UICore.core?.global.storage || localStorage
}
public static get adapterConfig() {
return this.adapter as AxiosAdapter
}
public static get clientId() {
return this.client
}
public static get passport() {
return this.passportUrl
}
public static get wxDistributer() {
return this.wxDistributerUrl
}
/**
* 构建 Passport 登出 URL
*/
public static buildPassport4Logout(redirect?: string) {
if (redirect) {
return `${this.passportUrl}?redirectUrl=${redirect}&logout=1`
}
return `${this.passportUrl}?logout=1`
}
public static forgetPassword() {
return `${this.passportUrl}/forget`
}
public static register() {
return `${this.passportUrl}/register?redirectUrl=${encodeURIComponent(
window.location.href,
)}`
}
public static buildActionParameter(parameter: { [key: string]: any }) {
return this.handler.buildActionParameter(parameter)
}
public static buildRows<T>(
rows: metaRow[],
predicts: SdkListRowPredict[] | SdkListRowPredictObject,
) {
return this.handler.buildRows<T>(rows, predicts)
}
public static buildRow<T>(
item: metaRow,
predicts: SdkListRowPredict[] | SdkListRowPredictObject,
) {
return this.handler.buildRow<T>(item, predicts)
}
}
APP_ENV=dev
NODE_ENV=development
VITE_APP_ENV=dev
VITE_APP_ID=dev_app_id
VITE_DEBUG=true
VITE_APP_PAY_URL=https://payment-api.teammix.com
VITE_APP_WWW_WORK_APP_URL=http://106.120.107.150:5000
VITE_APP_API_WORK_APP_URL=http://106.120.107.150:8090
VITE_APP_API_WORK_ORG_URL=http://106.120.107.150:7771
VITE_APP_USER_CENTER=http://106.120.107.150:8080
VITE_APP_UNIPLAT=http://hro.test-api.qqxb.jinsehuaqin.com:8800
VITE_APP_QQXB=http://test-qqxb-h5.hrs100.com
VITE_APP_H5_URL=https://static.qinqinxiaobao.com/flb-mp
VITE_APP_LAND_PAGE=https://static.qinqinxiaobao.com/flb-mp
VITE_APP_BJRSY_COLLECTION=https://bjcjtest.e-tecsun.com
VITE_APP_XB_URL=http://test-qqxb-h5.hrs100.com
VITE_APP_CLIENT_ID=qqqf-admin-web
VITE_APP_UNIPLAT_WEBSOCKET_URI=ws://hro.channel.jinsehuaqin.com:8080/ws
VITE_APP_CLIENT_SECRET=123456
VITE_APP_LOG_ENV=0
APP_ENV=production
NODE_ENV=production
VITE_APP_ENV=prod
VITE_DEBUG=false
VITE_APP_PAY_URL="https://payment-api.teammix.com"
VITE_APP_WWW_WORK_APP_URL = "https://passport.teammix.com"
VITE_APP_API_WORK_APP_URL = "https://userapi.teammix.com"
VITE_APP_USER_CENTER = "http://tmxlogin.teammix.com"
VITE_APP_UNIPLAT = "https://api-hro.qinqinxiaobao.com"
VITE_APP_QQXB = "http://test-qqxb-h5.hrs100.com"
VITE_APP_H5_URL = "https://static.qinqinxiaobao.com/flb-mp"
VITE_APP_LAND_PAGE = "https://static.qinqinxiaobao.com/flb-mp"
VITE_APP_UNIPLAT_WEBSOCKET_URI = "wss://channel.qinqinxiaobao.com/ws"
VITE_APP_XB_URL="https://qqxb-h5.qinqinxiaobao.com"
VITE_APP_CLIENT_ID = "qqqf-admin-web"
VITE_APP_CLIENT_SECRET = "qqxb#teammix#2019"
VITE_APP_LOG_ENV = 1
APP_ENV=staging
NODE_ENV=production
VITE_APP_ENV=pre
VITE_APP_ID=pre_app_id
VITE_DEBUG=true
VITE_APP_PAY_URL="https://payment-api.teammix.com"
VITE_APP_WWW_WORK_APP_URL = "https://pre-passport.teammix.com"
VITE_APP_API_WORK_APP_URL = "https://pre-userapi.teammix.com"
VITE_APP_API_WORK_ORG_URL = "http://106.120.107.150:7771"
VITE_APP_USER_CENTER = "https://pre-user.teammix.com"
VITE_APP_UNIPLAT = "https://pre-api-hro.qinqinxiaobao.com"
VITE_APP_QQXB = "http://test-qqxb-h5.hrs100.com"
VITE_APP_H5_URL = "https://static.qinqinxiaobao.com/flb-mp"
VITE_APP_LAND_PAGE = "https://static.qinqinxiaobao.com/flb-mp"
VITE_APP_XB_URL="https://pre-qqxb-h5.hrs100.com"
VITE_APP_FLB_URL = "http://pre-flb-h5.hrs100.com"
VITE_APP_CLIENT_ID = "qqqf-admin-web"
VITE_APP_UNIPLAT_WEBSOCKET_URI = "wss://pre-channel.qinqinxiaobao.com/ws"
VITE_APP_CLIENT_SECRET = "qqxb#teammix#2019"
VITE_APP_LOG_ENV = 3
APP_ENV=test
NODE_ENV=production
VITE_APP_ENV=test
VITE_APP_ID=test_app_id
VITE_DEBUG=true
VITE_APP_PAY_URL="https://payment-api.teammix.com"
VITE_APP_WWW_WORK_APP_URL = "http://106.120.107.150:5000"
VITE_APP_API_WORK_APP_URL = "http://106.120.107.150:8090"
VITE_APP_API_WORK_ORG_URL = "http://106.120.107.150:7771"
VITE_APP_USER_CENTER = "http://106.120.107.150:8080"
VITE_APP_UNIPLAT = "http://hro.test-api.qqxb.jinsehuaqin.com:8800"
VITE_APP_QQXB = "http://test-qqxb-h5.hrs100.com"
VITE_APP_H5_URL = "https://static.qinqinxiaobao.com/flb-mp"
VITE_APP_LAND_PAGE = "https://static.qinqinxiaobao.com/flb-mp"
VITE_APP_BJRSY_COLLECTION = "https://bjcjtest.e-tecsun.com"
VITE_APP_XB_URL="http://test-qqxb-h5.hrs100.com"
VITE_APP_CLIENT_ID = "qqqf-admin-web"
VITE_APP_UNIPLAT_WEBSOCKET_URI = "ws://hro.channel.jinsehuaqin.com:8080/ws"
VITE_APP_CLIENT_SECRET = "123456"
VITE_APP_LOG_ENV = 0
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_ENV: string
readonly VITE_APP_ID: string
readonly VITE_APP_UNIPLAT: string
readonly VITE_APP_CLIENT_ID: string
readonly VITE_APP_CLIENT_SECRET: string
readonly VITE_APP_LOG_ENV: string
readonly VITE_APP_UNIPLAT_WEBSOCKET_URI: string
readonly VITE_DEBUG: string
readonly VITE_APP_PAY_URL: string
readonly VITE_APP_WWW_WORK_APP_URL: string
readonly VITE_APP_API_WORK_APP_URL: string
readonly VITE_APP_API_WORK_ORG_URL: string
readonly VITE_APP_USER_CENTER: string
readonly VITE_APP_QQXB: string
readonly VITE_APP_H5_URL: string
readonly VITE_APP_LAND_PAGE: string
readonly VITE_APP_XB_URL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>亲亲企服管理后台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
{
"name": "qqqf-admin",
"type": "module",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"ant-design-vue": "^4.2.6",
"axios": "^1.7.9",
"pinia": "^2.1.7",
"vue": "^3.4.0",
"vue-router": "^4.3.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.0",
"typescript": "^5.6.3",
"unocss": "^0.58.0",
"vite": "^5.4.0",
"vue-tsc": "^2.1.0"
}
}
<template>
<div id="app">
<RouterView />
</div>
</template>
import type { LoginRegisterResult, VerifyImageResult } from "@common/sdk"
import { loginService, verifyService } from '@/src/api/request'
export type { LoginRegisterResult, VerifyImageResult }
/**
* 获取图形验证码
*/
export function getVerifyImage(): VerifyImageResult {
return verifyService.generateImage()
}
/**
* 发送短信验证码
*/
export function sendSmsCode(mobile: string, seed: string, verifycode: string) {
return verifyService.sendVerifyCode(mobile, seed, verifycode)
}
/**
* 验证码登录
*/
export function smsLogin(mobile: string, verifycode: string) {
return loginService.verifyCodeLogin(mobile, verifycode)
}
/**
* 密码登录
*/
export function passwordLogin(username: string, password: string) {
return loginService.login(username, password)
}
import type { SdkConfig } from '@common/sdk'
import { Sdk, TokenManager, webAdapter } from '@common/sdk'
import { createLoginService } from '@common/sdk/services/login-service'
import { createVerifyService } from '@common/sdk/services/verify-service'
/**
* qqqf-admin SDK 配置
*/
const sdkConfig: SdkConfig = {
uniplatApi: import.meta.env.VITE_APP_UNIPLAT,
rootEntrance: 'qqqf-admin',
logEnv: import.meta.env.VITE_APP_LOG_ENV,
clientId: import.meta.env.VITE_APP_CLIENT_ID,
domainService: {
subProjectName: 'qqqf',
serviceName: 'api',
},
}
/**
* 创建并初始化 SDK
*/
export const sdk = new Sdk(sdkConfig, webAdapter)
/**
* 创建服务(函数式,无需实例化)
*/
export const loginService = createLoginService(sdk.core, sdk.clientId)
export const verifyService = createVerifyService(sdk.core, sdk.clientId)
/**
* 初始化 Token(如果有)
*/
export function initToken() {
const token = TokenManager.hasToken()
if (token) {
sdk.core.loginByToken({
token: token as string,
})
}
return token
}
/**
* 获取 SDK 实例
*/
export function getSdk() {
return sdk
}
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import { initToken } from './api/request'
import App from './App.vue'
import router from './router'
// 初始化 SDK 和 Token(已在 api/request.ts 中封装)
initToken()
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
<template>
<div class="home-container">
<h1>qqqf-admin</h1>
<button class="test-btn" @click="testApiCall">测试 SDK 请求(携带 Token)</button>
<div v-if="result" class="result">
<h3>请求结果:</h3>
<pre>{{ result }}</pre>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { sdk } from '@/src/api/request'
const result = ref<any>(null)
async function testApiCall() {
try {
// 调用一个匿名接口测试
const res = await sdk.core
.domainService('qqqf', 'anonymous/api', 'test')
.get()
result.value = res
}
catch (e: any) {
result.value = { error: e?.message || '请求失败' }
}
}
</script>
<style scoped>
.home-container {
padding: 20px;
}
.test-btn {
padding: 12px 24px;
background: #667eea;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.result {
margin-top: 20px;
padding: 16px;
background: #f5f5f5;
border-radius: 4px;
}
.result pre {
white-space: pre-wrap;
word-break: break-all;
}
</style>
<template>
<div class="login-container">
<div class="login-card">
<h1 class="login-title">亲亲企服管理后台</h1>
<!-- 登录方式切换 -->
<div class="login-tabs">
<div
class="tab-item"
:class="{ active: loginType === 'sms' }"
@click="loginType = 'sms'"
>
验证码登录
</div>
<div
class="tab-item"
:class="{ active: loginType === 'password' }"
@click="loginType = 'password'"
>
密码登录
</div>
</div>
<!-- 验证码登录表单 -->
<form v-if="loginType === 'sms'" class="login-form" @submit.prevent="handleSmsLogin">
<div class="form-item">
<input
v-model="smsForm.mobile"
class="form-input"
type="tel"
placeholder="请输入手机号"
maxlength="11"
/>
</div>
<div class="form-item form-item-row">
<input
v-model="smsForm.verifycode"
class="form-input flex-1"
type="text"
placeholder="请输入图形验证码"
/>
<img
v-if="verifyImage.img"
:src="verifyImage.img"
class="verify-img"
alt="验证码"
@click="refreshVerifyImage"
/>
</div>
<div class="form-item form-item-row">
<input
v-model="smsForm.smsCode"
class="form-input flex-1"
type="text"
placeholder="请输入短信验证码"
maxlength="6"
/>
<button
class="sms-btn"
type="button"
:disabled="countdown > 0 || !smsForm.mobile"
@click="sendSms"
>
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
</button>
</div>
<button class="submit-btn" type="submit" :disabled="smsLoading">
{{ smsLoading ? '登录中...' : '登录' }}
</button>
</form>
<!-- 密码登录表单 -->
<form v-else class="login-form" @submit.prevent="handlePasswordLogin">
<div class="form-item">
<input
v-model="passwordForm.username"
class="form-input"
type="text"
placeholder="请输入用户名/手机号"
/>
</div>
<div class="form-item">
<input
v-model="passwordForm.password"
class="form-input"
type="password"
placeholder="请输入密码"
/>
</div>
<button class="submit-btn" type="submit" :disabled="passwordLoading">
{{ passwordLoading ? '登录中...' : '登录' }}
</button>
</form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getVerifyImage, passwordLogin, sendSmsCode, smsLogin } from '@/src/api/auth'
import { useAuthStore } from '@/src/stores/auth'
import { Toast } from '@/src/utils/toast'
const router = useRouter()
const route = useRoute()
const authStore = useAuthStore()
const loginType = ref<'sms' | 'password'>('sms')
// 验证码登录表单
const smsForm = ref({
mobile: '',
verifycode: '',
smsCode: '',
})
// 密码登录表单
const passwordForm = ref({
username: '',
password: '',
})
const smsLoading = ref(false)
const passwordLoading = ref(false)
const countdown = ref(0)
const verifyImage = ref({ img: '', seed: '' })
let timer: ReturnType<typeof setInterval> | null = null
// 获取图形验证码
async function refreshVerifyImage() {
try {
const res = await getVerifyImage()
verifyImage.value = res as any
}
catch (e) {
Toast.error('获取图形验证码失败')
}
}
// 发送短信验证码
async function sendSms() {
if (!smsForm.value.mobile) {
Toast.warning('请输入手机号')
return
}
if (!/^1\d{10}$/.test(smsForm.value.mobile)) {
Toast.warning('手机号格式不正确')
return
}
if (!smsForm.value.verifycode) {
Toast.warning('请输入图形验证码')
return
}
try {
await sendSmsCode(
smsForm.value.mobile,
verifyImage.value.seed,
smsForm.value.verifycode,
)
Toast.success('验证码已发送')
// 开始倒计时
countdown.value = 60
timer = setInterval(() => {
countdown.value--
if (countdown.value <= 0 && timer) {
clearInterval(timer)
timer = null
}
}, 1000)
}
catch (e: any) {
Toast.error(e?.message || '发送失败')
}
}
// 验证码登录
async function handleSmsLogin() {
if (!smsForm.value.mobile) {
Toast.warning('请输入手机号')
return
}
if (!smsForm.value.smsCode) {
Toast.warning('请输入验证码')
return
}
smsLoading.value = true
try {
const res = await smsLogin(smsForm.value.mobile, smsForm.value.smsCode)
const result = res as any
authStore.setToken(result.jwt)
Toast.success('登录成功')
const redirect = (route.query.redirect as string) || '/'
router.push(redirect)
}
catch (e: any) {
Toast.error(e?.message || '登录失败')
}
finally {
smsLoading.value = false
}
}
// 密码登录
async function handlePasswordLogin() {
if (!passwordForm.value.username) {
Toast.warning('请输入用户名')
return
}
if (!passwordForm.value.password) {
Toast.warning('请输入密码')
return
}
passwordLoading.value = true
try {
const res = await passwordLogin(
passwordForm.value.username,
passwordForm.value.password,
)
const result = res as any
authStore.setToken(result.jwt)
Toast.success('登录成功')
const redirect = (route.query.redirect as string) || '/'
router.push(redirect)
}
catch (e: any) {
Toast.error(e?.message || '登录失败')
}
finally {
passwordLoading.value = false
}
}
// 初始化图形验证码
refreshVerifyImage()
</script>
<style scoped>
.login-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-card {
width: 400px;
padding: 40px;
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.login-title {
text-align: center;
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0 0 30px;
}
.login-tabs {
display: flex;
margin-bottom: 24px;
border-bottom: 1px solid #eee;
}
.tab-item {
flex: 1;
text-align: center;
padding: 12px 0;
font-size: 16px;
color: #666;
cursor: pointer;
transition: all 0.3s;
}
.tab-item.active {
color: #667eea;
border-bottom: 2px solid #667eea;
}
.login-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.form-item {
width: 100%;
}
.form-item-row {
display: flex;
gap: 12px;
align-items: center;
}
.form-input {
width: 100%;
height: 44px;
padding: 0 16px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
outline: none;
transition: border-color 0.3s;
box-sizing: border-box;
}
.form-input:focus {
border-color: #667eea;
}
.flex-1 {
flex: 1;
}
.verify-img {
width: 120px;
height: 44px;
cursor: pointer;
border-radius: 4px;
}
.sms-btn {
width: 110px;
height: 44px;
border: 1px solid #667eea;
border-radius: 4px;
background: #fff;
color: #667eea;
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
white-space: nowrap;
}
.sms-btn:disabled {
border-color: #ccc;
color: #ccc;
cursor: not-allowed;
}
.submit-btn {
width: 100%;
height: 44px;
border: none;
border-radius: 4px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
font-size: 16px;
cursor: pointer;
transition: opacity 0.3s;
margin-top: 8px;
}
.submit-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>
import type { RouteRecordRaw } from 'vue-router'
import { TokenManager } from '@common/sdk'
import { createRouter, createWebHistory } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/login',
name: 'Login',
component: () => import('../pages/login/index.vue'),
meta: { title: '登录', requiresAuth: false },
},
{
path: '/',
name: 'Home',
component: () => import('../pages/index.vue'),
meta: { title: '首页', requiresAuth: true },
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
router.beforeEach((to, _from, next) => {
document.title = (to.meta.title as string) || '亲亲企服管理后台'
const token = TokenManager.hasToken()
if (to.meta.requiresAuth && !token) {
next({ path: '/login', query: { redirect: to.fullPath } })
}
else {
next()
}
})
export default router
import type { UserInfo } from '../types/auth'
import { TokenManager } from '@common/sdk'
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useAuthStore = defineStore('auth', () => {
const token = ref<string>(TokenManager.hasToken() || '')
const userInfo = ref<UserInfo | null>(null)
function setToken(newToken: string) {
token.value = newToken
TokenManager.saveToken2Storage(newToken)
}
function setUserInfo(info: UserInfo) {
userInfo.value = info
}
function logout() {
token.value = ''
userInfo.value = null
TokenManager.clearToken()
}
return { token, userInfo, setToken, setUserInfo, logout }
})
export interface UserInfo {
id: string
username: string
mobile?: string
avatar?: string
[key: string]: any
}
/**
* Toast 提示工具
* 替代 alert 弹窗,提供优雅的 Web Toast 提示
*/
interface ToastOptions {
message: string
type?: 'success' | 'error' | 'warning' | 'info'
duration?: number
}
let toastContainer: HTMLElement | null = null
let toastTimer: ReturnType<typeof setTimeout> | null = null
function getContainer() {
if (!toastContainer) {
toastContainer = document.createElement('div')
toastContainer.className = 'toast-container'
document.body.appendChild(toastContainer)
}
return toastContainer
}
function showToast(options: ToastOptions) {
const { message, type = 'info', duration = 2000 } = options
const container = getContainer()
// 清除之前的 toast
if (toastTimer) {
clearTimeout(toastTimer)
}
container.innerHTML = ''
const toast = document.createElement('div')
toast.className = `toast toast-${type}`
toast.textContent = message
container.appendChild(toast)
// 触发显示动画
requestAnimationFrame(() => {
toast.classList.add('toast-show')
})
// 自动隐藏
toastTimer = setTimeout(() => {
toast.classList.remove('toast-show')
setTimeout(() => {
container?.removeChild(toast)
}, 300)
}, duration)
}
export const Toast = {
success(message: string, duration?: number) {
showToast({ message, type: 'success', duration })
},
error(message: string, duration?: number) {
showToast({ message, type: 'error', duration })
},
warning(message: string, duration?: number) {
showToast({ message, type: 'warning', duration })
},
info(message: string, duration?: number) {
showToast({ message, type: 'info', duration })
},
}
// 注入全局样式
if (typeof document !== 'undefined' && !document.getElementById('toast-styles')) {
const style = document.createElement('style')
style.id = 'toast-styles'
style.textContent = `
.toast-container {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 9999;
pointer-events: none;
}
.toast {
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
color: #fff;
background: rgba(0, 0, 0, 0.8);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
opacity: 0;
transform: translateY(-20px);
transition: all 0.3s ease;
white-space: nowrap;
max-width: 80vw;
overflow: hidden;
text-overflow: ellipsis;
}
.toast-show {
opacity: 1;
transform: translateY(0);
}
.toast-success {
background: #52c41a;
}
.toast-error {
background: #ff4d4f;
}
.toast-warning {
background: #faad14;
}
.toast-info {
background: #1890ff;
}
`
document.head.appendChild(style)
}
{
"compilerOptions": {
"target": "ESNext",
"jsx": "preserve",
"lib": [
"ESNext",
"DOM"
],
"module": "ESNext",
"moduleResolution": "bundler",
"paths": {
"@/*": [
"./*"
]
},
"resolveJsonModule": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"isolatedModules": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts",
"src/**/*.vue",
"src/**/*.tsx",
"env.d.ts"
],
"exclude": [
"node_modules",
"dist",
"**/*.js"
]
}
import { resolve } from 'node:path'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, '.'),
},
},
build: {
outDir: 'dist',
},
})
<script lang="ts" setup> <script lang="ts" setup>
import { ClientId, PassportTokenController, UICore, uniAdapter } from "@common/sdk" import { TokenManager } from "@common/sdk"
import { onLaunch } from "@dcloudio/uni-app" import { onLaunch } from "@dcloudio/uni-app"
import { sdk } from "@/api/http" import { sdk } from "@/api/http"
...@@ -9,11 +9,7 @@ onLaunch(() => { ...@@ -9,11 +9,7 @@ onLaunch(() => {
}) })
function sdkInit() { function sdkInit() {
UICore.setupSdk(sdk.core, { const token = TokenManager.hasToken()
client: ClientId.Hrs100WechatMiniApp,
config: uniAdapter,
})
const token = PassportTokenController.hasToken()
if (token) { if (token) {
sdk.core.loginByToken({ sdk.core.loginByToken({
token: token as string, token: token as string,
......
import { SdkCore } from "@common/sdk" import { Sdk as SdkBase, TokenManager, uniAdapter } from "@common/sdk"
import { createLoginService } from "@common/sdk/services/login-service"
import { createVerifyService } from "@common/sdk/services/verify-service"
import { config } from "@/config" import { config } from "@/config"
class Sdk extends SdkCore { class Sdk extends SdkBase {
constructor() { constructor() {
super(config) super(config, uniAdapter)
} }
} }
const sdk = new Sdk() const sdk = new Sdk()
// 小程序 Storage 适配器(替代 localStorage)
class UniStorage implements Storage {
get length() {
const info = uni.getStorageInfoSync()
return info.keys.length
}
clear() {
uni.clearStorageSync()
}
getItem(key: string) {
try {
return uni.getStorageSync(key) || null
} catch {
return null
}
}
key(_index: number) {
const info = uni.getStorageInfoSync()
return info.keys[_index] || null
}
removeItem(key: string) {
uni.removeStorageSync(key)
}
setItem(key: string, value: string) {
uni.setStorageSync(key, value)
}
}
// 设置小程序存储实例(替代 localStorage)
TokenManager.setupStorage(new UniStorage())
// 创建服务(函数式,无需实例化)
export const loginService = createLoginService(sdk.core, sdk.clientId)
export const verifyService = createVerifyService(sdk.core, sdk.clientId)
export { sdk } export { sdk }
...@@ -43,9 +43,10 @@ ...@@ -43,9 +43,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { PassportTokenController, wechatLoginService } from "@common/sdk" import { TokenManager } from "@common/sdk"
import { onLoad } from "@dcloudio/uni-app" import { onLoad } from "@dcloudio/uni-app"
import { ref } from "vue" import { ref } from "vue"
import { miniProgramBindPhone } from "@/api/login-service"
import { config } from "@/config" import { config } from "@/config"
const agree = ref(false) const agree = ref(false)
...@@ -96,14 +97,15 @@ async function doWxLogin(e: any) { ...@@ -96,14 +97,15 @@ async function doWxLogin(e: any) {
}) })
}) })
// 调用绑定手机号登录接口 // 调用绑定手机号登录接口
const result = await wechatLoginService.miniProgramBindPhone( const result = await miniProgramBindPhone(
config.mpAppid || "", config.mpAppid || "",
code, code,
config.clientId,
e.detail.encryptedData, e.detail.encryptedData,
e.detail.iv, e.detail.iv,
) )
// 保存 token // 保存 token
PassportTokenController.saveToken2Storage(result.jwt) TokenManager.saveToken2Storage(result.jwt)
uni.hideLoading() uni.hideLoading()
uni.showToast({ title: "登录成功", icon: "success" }) uni.showToast({ title: "登录成功", icon: "success" })
setTimeout(() => { setTimeout(() => {
......
...@@ -141,9 +141,10 @@ ...@@ -141,9 +141,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { VerifyImageResult } from "@common/sdk" import type { VerifyImageResult } from "@common/sdk"
import { loginService, PassportTokenController, verifyService } from "@common/sdk" import { TokenManager } from "@common/sdk"
import { onLoad } from "@dcloudio/uni-app" import { onLoad } from "@dcloudio/uni-app"
import { computed, reactive, ref } from "vue" import { computed, reactive, ref } from "vue"
import { loginService, verifyService } from "@/api/http"
const activeTab = ref<"sms" | "password">("sms") const activeTab = ref<"sms" | "password">("sms")
...@@ -256,7 +257,7 @@ async function smsLogin() { ...@@ -256,7 +257,7 @@ async function smsLogin() {
smsLoading.value = true smsLoading.value = true
try { try {
const result = await loginService.verifyCodeLogin(smsModel.mobile, smsModel.code) const result = await loginService.verifyCodeLogin(smsModel.mobile, smsModel.code)
PassportTokenController.saveToken2Storage(result.jwt) TokenManager.saveToken2Storage(result.jwt)
uni.showToast({ title: "登录成功", icon: "success" }) uni.showToast({ title: "登录成功", icon: "success" })
setTimeout(() => { setTimeout(() => {
const redirect = uni.getStorageSync("loginRedirect") || "/pages/home/index" const redirect = uni.getStorageSync("loginRedirect") || "/pages/home/index"
...@@ -283,7 +284,7 @@ async function passwordLogin() { ...@@ -283,7 +284,7 @@ async function passwordLogin() {
pwdLoading.value = true pwdLoading.value = true
try { try {
const result = await loginService.login(passwordModel.username, passwordModel.password) const result = await loginService.login(passwordModel.username, passwordModel.password)
PassportTokenController.saveToken2Storage(result.jwt) TokenManager.saveToken2Storage(result.jwt)
uni.showToast({ title: "登录成功", icon: "success" }) uni.showToast({ title: "登录成功", icon: "success" })
setTimeout(() => { setTimeout(() => {
const redirect = uni.getStorageSync("loginRedirect") || "/pages/home/index" const redirect = uni.getStorageSync("loginRedirect") || "/pages/home/index"
......
...@@ -50,6 +50,10 @@ importers: ...@@ -50,6 +50,10 @@ importers:
uniplat-sdk: uniplat-sdk:
specifier: ^0.1.734-private specifier: ^0.1.734-private
version: 0.1.734-private version: 0.1.734-private
devDependencies:
'@types/lodash':
specifier: ^4.17.24
version: 4.17.24
common/utils: {} common/utils: {}
...@@ -328,6 +332,40 @@ importers: ...@@ -328,6 +332,40 @@ importers:
specifier: ^2.2.8 specifier: ^2.2.8
version: 2.2.12(typescript@5.9.3) version: 2.2.12(typescript@5.9.3)
packages/qqqf-admin:
dependencies:
ant-design-vue:
specifier: ^4.2.6
version: 4.2.6(vue@3.5.38(typescript@5.9.3))
axios:
specifier: ^0.27.2
version: 0.27.2
pinia:
specifier: ^2.1.7
version: 2.3.1(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3))
vue:
specifier: ^3.4.0
version: 3.5.38(typescript@5.9.3)
vue-router:
specifier: ^4.3.0
version: 4.6.4(vue@3.5.38(typescript@5.9.3))
devDependencies:
'@vitejs/plugin-vue':
specifier: ^5.1.0
version: 5.1.0(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))(vue@3.5.38(typescript@5.9.3))
typescript:
specifier: ^5.6.3
version: 5.9.3
unocss:
specifier: ^0.58.0
version: 0.58.9(postcss@8.5.15)(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))
vite:
specifier: ^5.4.0
version: 5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0)
vue-tsc:
specifier: ^2.1.0
version: 2.2.12(typescript@5.9.3)
packages/qqqf-mp: packages/qqqf-mp:
dependencies: dependencies:
'@common/sdk': '@common/sdk':
...@@ -1429,6 +1467,12 @@ packages: ...@@ -1429,6 +1467,12 @@ packages:
cpu: [ppc64] cpu: [ppc64]
os: [aix] os: [aix]
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.23.1': '@esbuild/aix-ppc64@0.23.1':
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1453,6 +1497,12 @@ packages: ...@@ -1453,6 +1497,12 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@esbuild/android-arm64@0.21.5':
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.23.1': '@esbuild/android-arm64@0.23.1':
resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1477,6 +1527,12 @@ packages: ...@@ -1477,6 +1527,12 @@ packages:
cpu: [arm] cpu: [arm]
os: [android] os: [android]
'@esbuild/android-arm@0.21.5':
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.23.1': '@esbuild/android-arm@0.23.1':
resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1501,6 +1557,12 @@ packages: ...@@ -1501,6 +1557,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [android] os: [android]
'@esbuild/android-x64@0.21.5':
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.23.1': '@esbuild/android-x64@0.23.1':
resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1525,6 +1587,12 @@ packages: ...@@ -1525,6 +1587,12 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@esbuild/darwin-arm64@0.21.5':
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.23.1': '@esbuild/darwin-arm64@0.23.1':
resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1549,6 +1617,12 @@ packages: ...@@ -1549,6 +1617,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@esbuild/darwin-x64@0.21.5':
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.23.1': '@esbuild/darwin-x64@0.23.1':
resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1573,6 +1647,12 @@ packages: ...@@ -1573,6 +1647,12 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [freebsd] os: [freebsd]
'@esbuild/freebsd-arm64@0.21.5':
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.23.1': '@esbuild/freebsd-arm64@0.23.1':
resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1597,6 +1677,12 @@ packages: ...@@ -1597,6 +1677,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@esbuild/freebsd-x64@0.21.5':
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.23.1': '@esbuild/freebsd-x64@0.23.1':
resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1621,6 +1707,12 @@ packages: ...@@ -1621,6 +1707,12 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@esbuild/linux-arm64@0.21.5':
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.23.1': '@esbuild/linux-arm64@0.23.1':
resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1645,6 +1737,12 @@ packages: ...@@ -1645,6 +1737,12 @@ packages:
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@esbuild/linux-arm@0.21.5':
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.23.1': '@esbuild/linux-arm@0.23.1':
resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1669,6 +1767,12 @@ packages: ...@@ -1669,6 +1767,12 @@ packages:
cpu: [ia32] cpu: [ia32]
os: [linux] os: [linux]
'@esbuild/linux-ia32@0.21.5':
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.23.1': '@esbuild/linux-ia32@0.23.1':
resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1693,6 +1797,12 @@ packages: ...@@ -1693,6 +1797,12 @@ packages:
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
'@esbuild/linux-loong64@0.21.5':
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.23.1': '@esbuild/linux-loong64@0.23.1':
resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1717,6 +1827,12 @@ packages: ...@@ -1717,6 +1827,12 @@ packages:
cpu: [mips64el] cpu: [mips64el]
os: [linux] os: [linux]
'@esbuild/linux-mips64el@0.21.5':
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.23.1': '@esbuild/linux-mips64el@0.23.1':
resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1741,6 +1857,12 @@ packages: ...@@ -1741,6 +1857,12 @@ packages:
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
'@esbuild/linux-ppc64@0.21.5':
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.23.1': '@esbuild/linux-ppc64@0.23.1':
resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1765,6 +1887,12 @@ packages: ...@@ -1765,6 +1887,12 @@ packages:
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
'@esbuild/linux-riscv64@0.21.5':
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.23.1': '@esbuild/linux-riscv64@0.23.1':
resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1789,6 +1917,12 @@ packages: ...@@ -1789,6 +1917,12 @@ packages:
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
'@esbuild/linux-s390x@0.21.5':
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.23.1': '@esbuild/linux-s390x@0.23.1':
resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1813,6 +1947,12 @@ packages: ...@@ -1813,6 +1947,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@esbuild/linux-x64@0.21.5':
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.23.1': '@esbuild/linux-x64@0.23.1':
resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1849,6 +1989,12 @@ packages: ...@@ -1849,6 +1989,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [netbsd] os: [netbsd]
'@esbuild/netbsd-x64@0.21.5':
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.23.1': '@esbuild/netbsd-x64@0.23.1':
resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1891,6 +2037,12 @@ packages: ...@@ -1891,6 +2037,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [openbsd] os: [openbsd]
'@esbuild/openbsd-x64@0.21.5':
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.23.1': '@esbuild/openbsd-x64@0.23.1':
resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1927,6 +2079,12 @@ packages: ...@@ -1927,6 +2079,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [sunos] os: [sunos]
'@esbuild/sunos-x64@0.21.5':
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.23.1': '@esbuild/sunos-x64@0.23.1':
resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1951,6 +2109,12 @@ packages: ...@@ -1951,6 +2109,12 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@esbuild/win32-arm64@0.21.5':
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.23.1': '@esbuild/win32-arm64@0.23.1':
resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1975,6 +2139,12 @@ packages: ...@@ -1975,6 +2139,12 @@ packages:
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@esbuild/win32-ia32@0.21.5':
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.23.1': '@esbuild/win32-ia32@0.23.1':
resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -1999,6 +2169,12 @@ packages: ...@@ -1999,6 +2169,12 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@esbuild/win32-x64@0.21.5':
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.23.1': '@esbuild/win32-x64@0.23.1':
resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -3460,6 +3636,9 @@ packages: ...@@ -3460,6 +3636,9 @@ packages:
'@types/linkify-it@5.0.0': '@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/lodash@4.17.24':
resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==}
'@types/markdown-it@14.1.2': '@types/markdown-it@14.1.2':
resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
...@@ -5336,6 +5515,11 @@ packages: ...@@ -5336,6 +5515,11 @@ packages:
engines: {node: '>=12'} engines: {node: '>=12'}
hasBin: true hasBin: true
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
hasBin: true
esbuild@0.23.1: esbuild@0.23.1:
resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
engines: {node: '>=18'} engines: {node: '>=18'}
...@@ -8980,6 +9164,37 @@ packages: ...@@ -8980,6 +9164,37 @@ packages:
terser: terser:
optional: true optional: true
vite@5.4.21:
resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
vite@7.3.5: vite@7.3.5:
resolution: {integrity: sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==} resolution: {integrity: sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
...@@ -11217,6 +11432,9 @@ snapshots: ...@@ -11217,6 +11432,9 @@ snapshots:
'@esbuild/aix-ppc64@0.20.2': '@esbuild/aix-ppc64@0.20.2':
optional: true optional: true
'@esbuild/aix-ppc64@0.21.5':
optional: true
'@esbuild/aix-ppc64@0.23.1': '@esbuild/aix-ppc64@0.23.1':
optional: true optional: true
...@@ -11229,6 +11447,9 @@ snapshots: ...@@ -11229,6 +11447,9 @@ snapshots:
'@esbuild/android-arm64@0.20.2': '@esbuild/android-arm64@0.20.2':
optional: true optional: true
'@esbuild/android-arm64@0.21.5':
optional: true
'@esbuild/android-arm64@0.23.1': '@esbuild/android-arm64@0.23.1':
optional: true optional: true
...@@ -11241,6 +11462,9 @@ snapshots: ...@@ -11241,6 +11462,9 @@ snapshots:
'@esbuild/android-arm@0.20.2': '@esbuild/android-arm@0.20.2':
optional: true optional: true
'@esbuild/android-arm@0.21.5':
optional: true
'@esbuild/android-arm@0.23.1': '@esbuild/android-arm@0.23.1':
optional: true optional: true
...@@ -11253,6 +11477,9 @@ snapshots: ...@@ -11253,6 +11477,9 @@ snapshots:
'@esbuild/android-x64@0.20.2': '@esbuild/android-x64@0.20.2':
optional: true optional: true
'@esbuild/android-x64@0.21.5':
optional: true
'@esbuild/android-x64@0.23.1': '@esbuild/android-x64@0.23.1':
optional: true optional: true
...@@ -11265,6 +11492,9 @@ snapshots: ...@@ -11265,6 +11492,9 @@ snapshots:
'@esbuild/darwin-arm64@0.20.2': '@esbuild/darwin-arm64@0.20.2':
optional: true optional: true
'@esbuild/darwin-arm64@0.21.5':
optional: true
'@esbuild/darwin-arm64@0.23.1': '@esbuild/darwin-arm64@0.23.1':
optional: true optional: true
...@@ -11277,6 +11507,9 @@ snapshots: ...@@ -11277,6 +11507,9 @@ snapshots:
'@esbuild/darwin-x64@0.20.2': '@esbuild/darwin-x64@0.20.2':
optional: true optional: true
'@esbuild/darwin-x64@0.21.5':
optional: true
'@esbuild/darwin-x64@0.23.1': '@esbuild/darwin-x64@0.23.1':
optional: true optional: true
...@@ -11289,6 +11522,9 @@ snapshots: ...@@ -11289,6 +11522,9 @@ snapshots:
'@esbuild/freebsd-arm64@0.20.2': '@esbuild/freebsd-arm64@0.20.2':
optional: true optional: true
'@esbuild/freebsd-arm64@0.21.5':
optional: true
'@esbuild/freebsd-arm64@0.23.1': '@esbuild/freebsd-arm64@0.23.1':
optional: true optional: true
...@@ -11301,6 +11537,9 @@ snapshots: ...@@ -11301,6 +11537,9 @@ snapshots:
'@esbuild/freebsd-x64@0.20.2': '@esbuild/freebsd-x64@0.20.2':
optional: true optional: true
'@esbuild/freebsd-x64@0.21.5':
optional: true
'@esbuild/freebsd-x64@0.23.1': '@esbuild/freebsd-x64@0.23.1':
optional: true optional: true
...@@ -11313,6 +11552,9 @@ snapshots: ...@@ -11313,6 +11552,9 @@ snapshots:
'@esbuild/linux-arm64@0.20.2': '@esbuild/linux-arm64@0.20.2':
optional: true optional: true
'@esbuild/linux-arm64@0.21.5':
optional: true
'@esbuild/linux-arm64@0.23.1': '@esbuild/linux-arm64@0.23.1':
optional: true optional: true
...@@ -11325,6 +11567,9 @@ snapshots: ...@@ -11325,6 +11567,9 @@ snapshots:
'@esbuild/linux-arm@0.20.2': '@esbuild/linux-arm@0.20.2':
optional: true optional: true
'@esbuild/linux-arm@0.21.5':
optional: true
'@esbuild/linux-arm@0.23.1': '@esbuild/linux-arm@0.23.1':
optional: true optional: true
...@@ -11337,6 +11582,9 @@ snapshots: ...@@ -11337,6 +11582,9 @@ snapshots:
'@esbuild/linux-ia32@0.20.2': '@esbuild/linux-ia32@0.20.2':
optional: true optional: true
'@esbuild/linux-ia32@0.21.5':
optional: true
'@esbuild/linux-ia32@0.23.1': '@esbuild/linux-ia32@0.23.1':
optional: true optional: true
...@@ -11349,6 +11597,9 @@ snapshots: ...@@ -11349,6 +11597,9 @@ snapshots:
'@esbuild/linux-loong64@0.20.2': '@esbuild/linux-loong64@0.20.2':
optional: true optional: true
'@esbuild/linux-loong64@0.21.5':
optional: true
'@esbuild/linux-loong64@0.23.1': '@esbuild/linux-loong64@0.23.1':
optional: true optional: true
...@@ -11361,6 +11612,9 @@ snapshots: ...@@ -11361,6 +11612,9 @@ snapshots:
'@esbuild/linux-mips64el@0.20.2': '@esbuild/linux-mips64el@0.20.2':
optional: true optional: true
'@esbuild/linux-mips64el@0.21.5':
optional: true
'@esbuild/linux-mips64el@0.23.1': '@esbuild/linux-mips64el@0.23.1':
optional: true optional: true
...@@ -11373,6 +11627,9 @@ snapshots: ...@@ -11373,6 +11627,9 @@ snapshots:
'@esbuild/linux-ppc64@0.20.2': '@esbuild/linux-ppc64@0.20.2':
optional: true optional: true
'@esbuild/linux-ppc64@0.21.5':
optional: true
'@esbuild/linux-ppc64@0.23.1': '@esbuild/linux-ppc64@0.23.1':
optional: true optional: true
...@@ -11385,6 +11642,9 @@ snapshots: ...@@ -11385,6 +11642,9 @@ snapshots:
'@esbuild/linux-riscv64@0.20.2': '@esbuild/linux-riscv64@0.20.2':
optional: true optional: true
'@esbuild/linux-riscv64@0.21.5':
optional: true
'@esbuild/linux-riscv64@0.23.1': '@esbuild/linux-riscv64@0.23.1':
optional: true optional: true
...@@ -11397,6 +11657,9 @@ snapshots: ...@@ -11397,6 +11657,9 @@ snapshots:
'@esbuild/linux-s390x@0.20.2': '@esbuild/linux-s390x@0.20.2':
optional: true optional: true
'@esbuild/linux-s390x@0.21.5':
optional: true
'@esbuild/linux-s390x@0.23.1': '@esbuild/linux-s390x@0.23.1':
optional: true optional: true
...@@ -11409,6 +11672,9 @@ snapshots: ...@@ -11409,6 +11672,9 @@ snapshots:
'@esbuild/linux-x64@0.20.2': '@esbuild/linux-x64@0.20.2':
optional: true optional: true
'@esbuild/linux-x64@0.21.5':
optional: true
'@esbuild/linux-x64@0.23.1': '@esbuild/linux-x64@0.23.1':
optional: true optional: true
...@@ -11427,6 +11693,9 @@ snapshots: ...@@ -11427,6 +11693,9 @@ snapshots:
'@esbuild/netbsd-x64@0.20.2': '@esbuild/netbsd-x64@0.20.2':
optional: true optional: true
'@esbuild/netbsd-x64@0.21.5':
optional: true
'@esbuild/netbsd-x64@0.23.1': '@esbuild/netbsd-x64@0.23.1':
optional: true optional: true
...@@ -11448,6 +11717,9 @@ snapshots: ...@@ -11448,6 +11717,9 @@ snapshots:
'@esbuild/openbsd-x64@0.20.2': '@esbuild/openbsd-x64@0.20.2':
optional: true optional: true
'@esbuild/openbsd-x64@0.21.5':
optional: true
'@esbuild/openbsd-x64@0.23.1': '@esbuild/openbsd-x64@0.23.1':
optional: true optional: true
...@@ -11466,6 +11738,9 @@ snapshots: ...@@ -11466,6 +11738,9 @@ snapshots:
'@esbuild/sunos-x64@0.20.2': '@esbuild/sunos-x64@0.20.2':
optional: true optional: true
'@esbuild/sunos-x64@0.21.5':
optional: true
'@esbuild/sunos-x64@0.23.1': '@esbuild/sunos-x64@0.23.1':
optional: true optional: true
...@@ -11478,6 +11753,9 @@ snapshots: ...@@ -11478,6 +11753,9 @@ snapshots:
'@esbuild/win32-arm64@0.20.2': '@esbuild/win32-arm64@0.20.2':
optional: true optional: true
'@esbuild/win32-arm64@0.21.5':
optional: true
'@esbuild/win32-arm64@0.23.1': '@esbuild/win32-arm64@0.23.1':
optional: true optional: true
...@@ -11490,6 +11768,9 @@ snapshots: ...@@ -11490,6 +11768,9 @@ snapshots:
'@esbuild/win32-ia32@0.20.2': '@esbuild/win32-ia32@0.20.2':
optional: true optional: true
'@esbuild/win32-ia32@0.21.5':
optional: true
'@esbuild/win32-ia32@0.23.1': '@esbuild/win32-ia32@0.23.1':
optional: true optional: true
...@@ -11502,6 +11783,9 @@ snapshots: ...@@ -11502,6 +11783,9 @@ snapshots:
'@esbuild/win32-x64@0.20.2': '@esbuild/win32-x64@0.20.2':
optional: true optional: true
'@esbuild/win32-x64@0.21.5':
optional: true
'@esbuild/win32-x64@0.23.1': '@esbuild/win32-x64@0.23.1':
optional: true optional: true
...@@ -13239,6 +13523,8 @@ snapshots: ...@@ -13239,6 +13523,8 @@ snapshots:
'@types/linkify-it@5.0.0': {} '@types/linkify-it@5.0.0': {}
'@types/lodash@4.17.24': {}
'@types/markdown-it@14.1.2': '@types/markdown-it@14.1.2':
dependencies: dependencies:
'@types/linkify-it': 5.0.0 '@types/linkify-it': 5.0.0
...@@ -13417,6 +13703,16 @@ snapshots: ...@@ -13417,6 +13703,16 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
'@unocss/astro@0.58.9(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))':
dependencies:
'@unocss/core': 0.58.9
'@unocss/reset': 0.58.9
'@unocss/vite': 0.58.9(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))
optionalDependencies:
vite: 5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0)
transitivePeerDependencies:
- rollup
'@unocss/astro@0.64.1(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))': '@unocss/astro@0.64.1(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))':
dependencies: dependencies:
'@unocss/core': 0.64.1 '@unocss/core': 0.64.1
...@@ -13864,6 +14160,22 @@ snapshots: ...@@ -13864,6 +14160,22 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
'@unocss/vite@0.58.9(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))':
dependencies:
'@ampproject/remapping': 2.3.0
'@rollup/pluginutils': 5.4.0(rollup@4.62.0)
'@unocss/config': 0.58.9
'@unocss/core': 0.58.9
'@unocss/inspector': 0.58.9
'@unocss/scope': 0.58.9
'@unocss/transformer-directives': 0.58.9
chokidar: 3.6.0
fast-glob: 3.3.3
magic-string: 0.30.21
vite: 5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0)
transitivePeerDependencies:
- rollup
'@unocss/vite@0.64.1(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))': '@unocss/vite@0.64.1(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))':
dependencies: dependencies:
'@ampproject/remapping': 2.3.0 '@ampproject/remapping': 2.3.0
...@@ -14041,6 +14353,11 @@ snapshots: ...@@ -14041,6 +14353,11 @@ snapshots:
vite: 5.2.8(@types/node@22.20.0)(sass@1.101.0)(terser@5.48.0) vite: 5.2.8(@types/node@22.20.0)(sass@1.101.0)(terser@5.48.0)
vue: 3.5.38(typescript@5.9.3) vue: 3.5.38(typescript@5.9.3)
'@vitejs/plugin-vue@5.1.0(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))(vue@3.5.38(typescript@5.9.3))':
dependencies:
vite: 5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0)
vue: 3.5.38(typescript@5.9.3)
'@vitejs/plugin-vue@6.0.7(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))': '@vitejs/plugin-vue@6.0.7(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.1 '@rolldown/pluginutils': 1.0.1
...@@ -15449,6 +15766,32 @@ snapshots: ...@@ -15449,6 +15766,32 @@ snapshots:
'@esbuild/win32-ia32': 0.20.2 '@esbuild/win32-ia32': 0.20.2
'@esbuild/win32-x64': 0.20.2 '@esbuild/win32-x64': 0.20.2
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
'@esbuild/android-arm': 0.21.5
'@esbuild/android-arm64': 0.21.5
'@esbuild/android-x64': 0.21.5
'@esbuild/darwin-arm64': 0.21.5
'@esbuild/darwin-x64': 0.21.5
'@esbuild/freebsd-arm64': 0.21.5
'@esbuild/freebsd-x64': 0.21.5
'@esbuild/linux-arm': 0.21.5
'@esbuild/linux-arm64': 0.21.5
'@esbuild/linux-ia32': 0.21.5
'@esbuild/linux-loong64': 0.21.5
'@esbuild/linux-mips64el': 0.21.5
'@esbuild/linux-ppc64': 0.21.5
'@esbuild/linux-riscv64': 0.21.5
'@esbuild/linux-s390x': 0.21.5
'@esbuild/linux-x64': 0.21.5
'@esbuild/netbsd-x64': 0.21.5
'@esbuild/openbsd-x64': 0.21.5
'@esbuild/sunos-x64': 0.21.5
'@esbuild/win32-arm64': 0.21.5
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
esbuild@0.23.1: esbuild@0.23.1:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.23.1 '@esbuild/aix-ppc64': 0.23.1
...@@ -19754,6 +20097,35 @@ snapshots: ...@@ -19754,6 +20097,35 @@ snapshots:
- rollup - rollup
- supports-color - supports-color
unocss@0.58.9(postcss@8.5.15)(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0)):
dependencies:
'@unocss/astro': 0.58.9(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))
'@unocss/cli': 0.58.9(rollup@4.62.0)
'@unocss/core': 0.58.9
'@unocss/extractor-arbitrary-variants': 0.58.9
'@unocss/postcss': 0.58.9(postcss@8.5.15)
'@unocss/preset-attributify': 0.58.9
'@unocss/preset-icons': 0.58.9
'@unocss/preset-mini': 0.58.9
'@unocss/preset-tagify': 0.58.9
'@unocss/preset-typography': 0.58.9
'@unocss/preset-uno': 0.58.9
'@unocss/preset-web-fonts': 0.58.9
'@unocss/preset-wind': 0.58.9
'@unocss/reset': 0.58.9
'@unocss/transformer-attributify-jsx': 0.58.9
'@unocss/transformer-attributify-jsx-babel': 0.58.9
'@unocss/transformer-compile-class': 0.58.9
'@unocss/transformer-directives': 0.58.9
'@unocss/transformer-variant-group': 0.58.9
'@unocss/vite': 0.58.9(rollup@4.62.0)(vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0))
optionalDependencies:
vite: 5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0)
transitivePeerDependencies:
- postcss
- rollup
- supports-color
unocss@0.64.1(@unocss/webpack@0.64.1(rollup@4.62.0)(webpack@5.107.2(esbuild@0.23.1)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)): unocss@0.64.1(@unocss/webpack@0.64.1(rollup@4.62.0)(webpack@5.107.2(esbuild@0.23.1)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)):
dependencies: dependencies:
'@unocss/astro': 0.64.1(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)) '@unocss/astro': 0.64.1(rollup@4.62.0)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))
...@@ -20086,6 +20458,17 @@ snapshots: ...@@ -20086,6 +20458,17 @@ snapshots:
sass: 1.101.0 sass: 1.101.0
terser: 5.48.0 terser: 5.48.0
vite@5.4.21(@types/node@25.9.3)(sass@1.101.0)(terser@5.48.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.15
rollup: 4.62.0
optionalDependencies:
'@types/node': 25.9.3
fsevents: 2.3.3
sass: 1.101.0
terser: 5.48.0
vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0): vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(sass@1.101.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0):
dependencies: dependencies:
esbuild: 0.27.7 esbuild: 0.27.7
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment