Commit 15d3f72c by chunhong.mu

feat(*): 新增管理后台项目,完善基础初始化与适配

- 新增 qqqf-admin 管理后台完整项目结构
- 新增 Web 平台 Axios 适配器适配 Web 环境
- 修复 common sdk 中验证码、文件操作、更新管理器等适配问题
- 补充 commitlint 配置项,新增 qqqf-admin 作用域
- 为 common sdk 补充类型定义与导出优化
parent fc794e28
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'],
}, },
} }
...@@ -7,5 +7,8 @@ ...@@ -7,5 +7,8 @@
"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"
} }
} }
...@@ -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(),
......
...@@ -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}`
......
...@@ -65,13 +65,14 @@ export { ClientId, Environment, UICore, wxDistributerUrlConfig } from "./ui-core ...@@ -65,13 +65,14 @@ export { ClientId, Environment, UICore, wxDistributerUrlConfig } from "./ui-core
export { uniAdapter } from "./uni-adapter" export { uniAdapter } from "./uni-adapter"
// 小程序版本更新 // 小程序版本更新
export { updateManager } from "./update-manager" export { updateManager } from "./update-manager"
// 验证码服务 // 验证码服务
export { verifyService } from "./verify-service" export { verifyService } from "./verify-service"
export type { VerifyImageResult } from "./verify-service" export type { VerifyImageResult } from "./verify-service"
export { webAdapter } from "./web-adapter"
// 微信登录服务 // 微信登录服务
export { wechatLoginService } from "./wechat-login-service" export { wechatLoginService } from "./wechat-login-service"
export type { RegisterChannel, WechatLoginResult } from "./wechat-login-service" export type { WechatLoginResult } from "./wechat-login-service"
...@@ -12,7 +12,6 @@ import { ...@@ -12,7 +12,6 @@ import {
} from "uniplat-sdk" } from "uniplat-sdk"
import { Tree } from "uniplat-sdk/build/main/model/tree/tree" import { Tree } from "uniplat-sdk/build/main/model/tree/tree"
import { buildFilePath, buildImage } from "./image-builder" import { buildFilePath, buildImage } from "./image-builder"
import { uniAdapter } from "./uni-adapter"
export class SdkCore { export class SdkCore {
private uniplatSdk!: UniplatSdk private uniplatSdk!: UniplatSdk
...@@ -20,22 +19,17 @@ export class SdkCore { ...@@ -20,22 +19,17 @@ export class SdkCore {
private token!: string private token!: string
public orgId!: number public orgId!: number
constructor(config?: SdkConfig) { constructor(config?: SdkConfig, adapter?: AxiosAdapter) {
if (config) { if (config) {
this.init(config) this.init(config, adapter)
} }
} }
public init(config: SdkConfig) { public init(config: SdkConfig, adapter?: AxiosAdapter) {
const baseUrl = config.uniplatApi const baseUrl = config.uniplatApi
this.uniplatSdk = new UniplatSdk({ sse: false }) this.uniplatSdk = new UniplatSdk({ sse: false })
this.uniplatSdk.global.baseUrl = baseUrl this.uniplatSdk.global.baseUrl = baseUrl
let adapter: AxiosAdapter | undefined
// #ifdef MP
adapter = uniAdapter
// #endif
this.uniplatSdk.connect({ this.uniplatSdk.connect({
baseUrl, baseUrl,
axiosAdapter: adapter, axiosAdapter: adapter,
...@@ -43,9 +37,7 @@ export class SdkCore { ...@@ -43,9 +37,7 @@ export class SdkCore {
refreshInterval: 10 * 60 * 1000, refreshInterval: 10 * 60 * 1000,
}) })
// #ifndef MP
this.uniplatSdk.getAxios().defaults.timeout = 10e3 this.uniplatSdk.getAxios().defaults.timeout = 10e3
// #endif
this.uniplatSdk.global.rootEntrance = config.rootEntrance this.uniplatSdk.global.rootEntrance = config.rootEntrance
} }
...@@ -136,4 +128,11 @@ export class SdkCore { ...@@ -136,4 +128,11 @@ export class SdkCore {
public decodeToken<T>(token: string) { public decodeToken<T>(token: string) {
return decodeJwt<T>(token) return decodeJwt<T>(token)
} }
/**
* 获取 Axios 实例(用于 Web 项目直接调用)
*/
public getAxios() {
return this.uniplatSdk.getAxios()
}
} }
import { last } from "lodash"
import { ref } from "vue" import { ref } from "vue"
const defaultShareData = { const defaultShareData = {
...@@ -23,10 +22,12 @@ export function setShareData(shareData: { ...@@ -23,10 +22,12 @@ export function setShareData(shareData: {
path?: string path?: string
imageUrl?: string imageUrl?: string
}) { }) {
const p = last(getCurrentPages()) const pages = getCurrentPages()
const p = pages[pages.length - 1]
const route = (p as any).route || ""
finalShareData.value = { finalShareData.value = {
...finalShareData.value, ...finalShareData.value,
[p!.route]: { [route]: {
...defaultShareData, ...defaultShareData,
...shareData, ...shareData,
}, },
...@@ -39,8 +40,10 @@ export function setShareData(shareData: { ...@@ -39,8 +40,10 @@ export function setShareData(shareData: {
export function createShareMixin() { export function createShareMixin() {
return { return {
onShareAppMessage() { onShareAppMessage() {
const p = last(getCurrentPages()) const pages = getCurrentPages()
return finalShareData.value[p!.route] || defaultShareData const p = pages[pages.length - 1]
const route = (p as any).route || ""
return finalShareData.value[route] || defaultShareData
}, },
} }
} }
...@@ -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
......
...@@ -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()
} }
......
...@@ -23,7 +23,11 @@ export class VerifyService { ...@@ -23,7 +23,11 @@ export class VerifyService {
* 生成图形验证码 * 生成图形验证码
*/ */
public generateImage(): VerifyImageResult { public generateImage(): VerifyImageResult {
return UICore.core.getVerifyImageAndSeed() const result = UICore.core.getVerifyImageAndSeed() as any
return {
img: result.img,
seed: String(result.seed),
}
} }
/** /**
......
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)
})
}
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 "@common/sdk"
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 { ClientId, PassportTokenController, SdkCore, UICore, webAdapter } from '@common/sdk'
/**
* 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 SdkCore(sdkConfig, webAdapter)
/**
* 注册 Web 适配器到 UICore
*/
UICore.setupSdk(sdk.core, {
client: ClientId.None,
config: webAdapter,
})
/**
* 初始化 Token(如果有)
*/
export function initToken() {
const token = PassportTokenController.hasToken()
if (token) {
sdk.core.loginByToken({
token: token as string,
})
}
return token
}
/**
* 获取 SDK 实例
*/
export function getSdk() {
return sdk
}
/**
* 获取 UICore 实例
*/
export function getUICore() {
return UICore
}
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 { PassportTokenController } 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 = PassportTokenController.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 { PassportTokenController } from '@common/sdk'
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useAuthStore = defineStore('auth', () => {
const token = ref<string>(PassportTokenController.hasToken() || '')
const userInfo = ref<UserInfo | null>(null)
function setToken(newToken: string) {
token.value = newToken
PassportTokenController.saveToken2Storage(newToken)
}
function setUserInfo(info: UserInfo) {
userInfo.value = info
}
function logout() {
token.value = ''
userInfo.value = null
PassportTokenController.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',
},
})
import { SdkCore } from "@common/sdk" import { SdkCore, uniAdapter } from "@common/sdk"
import { config } from "@/config" import { config } from "@/config"
class Sdk extends SdkCore { class Sdk extends SdkCore {
constructor() { constructor() {
super(config) super(config, uniAdapter)
} }
} }
......
...@@ -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