feat: add a new feature
This commit is contained in:
parent
1ffc4237ca
commit
b44e90451d
29
.vscode/launch.json
vendored
Normal file
29
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Filename: /Users/kurosago/Code/Self/uniViteTemplate/.vscode/launch.json
|
||||
* Path: /Users/kurosago/Code/Self/uniViteTemplate
|
||||
* Created Date: Thursday, June 20th 2024, 9:26:43 pm
|
||||
* Author: KuroSago
|
||||
*
|
||||
* Copyright (c) 2024 self.
|
||||
*/
|
||||
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Vue Debugger",
|
||||
"url": "http://localhost:9527",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "TS Debugger",
|
||||
"runtimeExecutable": "tsx",
|
||||
"skipFiles": ["<node_internals>/**", "${workspaceFolder}/node_modules/**"],
|
||||
"program": "${file}"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -4,7 +4,6 @@
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"editor.formatOnSave": false,
|
||||
"prettier.enable": false,
|
||||
"unocss.root": ["./"],
|
||||
|
||||
@ -39,7 +39,7 @@ export default antfu({
|
||||
'./dist/*',
|
||||
'./.vscode/*',
|
||||
'./.idea/*',
|
||||
'**/androidPrivacy.json',
|
||||
'./src/androidPrivacy.json',
|
||||
'README.md',
|
||||
],
|
||||
});
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
"message": "__请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款, 包括但不限于:为了更好的向你提供服务, 我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/>__你可阅读<a href=\"\">《服务协议》</a>和<a href=\"\">《隐私政策》</a>了解详细信息。如果你同意, 请点击下面按钮开始接受我们的服务。",
|
||||
"buttonAccept": "同意并接受",
|
||||
"buttonRefuse": "暂不同意",
|
||||
// HX 3.4.13之后版本新增, system 使用系统webview 打开隐私协议链接, 默认使用uni-app内置web组件
|
||||
"hrefLoader": "default",
|
||||
"second": {
|
||||
"title": "确认提示",
|
||||
|
||||
23
src/enums/UI.ts
Normal file
23
src/enums/UI.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// S、M、L、XL、XXL、XXXL
|
||||
// S: Small 小 ;M: Middle 中;L: Large 大;XL: extra large 加大;多个X则代表多重加大码,X越多,码数越大。
|
||||
export enum Size {
|
||||
S = 's',
|
||||
M = 'm',
|
||||
L = 'l',
|
||||
XL = 'xl',
|
||||
XXl = 'xxl',
|
||||
XXXL = 'xxxl',
|
||||
}
|
||||
|
||||
export enum UNOCSS_THEME_TYPE {
|
||||
SCREENS = 'screens',
|
||||
COLORS = 'colors',
|
||||
SPACING = 'spacing',
|
||||
BORDERRADIUS = 'borderRadius',
|
||||
FONTFAMILY = 'fontFamily',
|
||||
}
|
||||
|
||||
export enum THEME_MODEL {
|
||||
LIGHT = 'light',
|
||||
DARK = 'dark',
|
||||
}
|
||||
10
src/enums/apiEnum.ts
Normal file
10
src/enums/apiEnum.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export enum ApiVersionEnum {
|
||||
V1 = 'v1',
|
||||
}
|
||||
|
||||
export enum ApiPathEnum {
|
||||
ADMIN = 'admin',
|
||||
USERS = 'users',
|
||||
PORTAL = 'portal',
|
||||
RIDERS = 'riders',
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
// token key
|
||||
export const TOKEN_KEY = 'TOKEN__';
|
||||
|
||||
// user info key
|
||||
export const USER_INFO_KEY = 'USER__INFO__';
|
||||
112
src/enums/platformEnum.ts
Normal file
112
src/enums/platformEnum.ts
Normal file
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 平台
|
||||
*/
|
||||
export enum PLATFORMS {
|
||||
DEFAULT = 'DEFAULT' /* 默认 */,
|
||||
VUE3 = 'VUE3' /* HBuilderX 3.2.0+ */,
|
||||
APP_PLUS = 'APP-PLUS' /* App */,
|
||||
APP_PLUS_NVUE = 'APP-PLUS-NVUE' /* App nvue 页面 */,
|
||||
APP_NVUE = 'APP-NVUE' /* App nvue 页面 */,
|
||||
H5 = 'H5' /* H5 */,
|
||||
MP_WEIXIN = 'MP-WEIXIN' /* 微信小程序 */,
|
||||
MP_ALIPAY = 'MP-ALIPAY' /* 支付宝小程序 */,
|
||||
MP_BAIDU = 'MP_BAIDU' /* 百度小程序 */,
|
||||
MP_TOUTIAO = 'MP-TOUTIAO' /* 字节跳动小程序 */,
|
||||
MP_LARK = 'MP-LARK' /* 飞书小程序 */,
|
||||
MP_QQ = 'MP-QQ' /* QQ小程序 */,
|
||||
MP_KUAISHOU = 'MP-KUAISHOU' /* 快手小程序 */,
|
||||
MP_JD = 'MP-JD' /* 京东小程序 */,
|
||||
MP_360 = 'MP-360' /* 360小程序 */,
|
||||
MP = 'MP' /* 微信小程序/支付宝小程序/百度小程序/字节跳动小程序/飞书小程序/QQ小程序/360小程序 */,
|
||||
QUICKAPP_WEBVIEW = 'QUICKAPP-WEBVIEW' /* 快应用通用(包含联盟、华为) */,
|
||||
QUICKAPP_WEBVIEW_UNION = 'QUICKAPP-WEBVIEW-UNION' /* 快应用联盟 */,
|
||||
QUICKAPP_WEBVIEW_HUAWEI = 'QUICKAPP-WEBVIEW-HUAWEI' /* 快应用华为 */,
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台环境
|
||||
* @constructor
|
||||
*/
|
||||
function PLATFORM_ENV() {
|
||||
let platform = PLATFORMS.DEFAULT;
|
||||
|
||||
/* #ifdef VUE3 */
|
||||
platform = PLATFORMS.VUE3;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef APP-PLUS */
|
||||
platform = PLATFORMS.APP_PLUS;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef APP-PLUS-NVUE */
|
||||
platform = PLATFORMS.APP_PLUS_NVUE;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
platform = PLATFORMS.APP_NVUE;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef H5 */
|
||||
platform = PLATFORMS.H5;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP */
|
||||
platform = PLATFORMS.MP;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-WEIXIN */
|
||||
platform = PLATFORMS.MP_WEIXIN;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-ALIPAY */
|
||||
platform = PLATFORMS.MP_ALIPAY;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP_BAIDU */
|
||||
platform = PLATFORMS.MP_BAIDU;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-TOUTIAO */
|
||||
platform = PLATFORMS.MP_TOUTIAO;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-LARK */
|
||||
platform = PLATFORMS.MP_LARK;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-QQ */
|
||||
platform = PLATFORMS.MP_QQ;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-KUAISHOU */
|
||||
platform = PLATFORMS.MP_KUAISHOU;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-JD */
|
||||
platform = PLATFORMS.MP_JD;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-360 */
|
||||
platform = PLATFORMS.MP_360;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef QUICKAPP-WEBVIEW */
|
||||
platform = PLATFORMS.QUICKAPP_WEBVIEW;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef QUICKAPP-WEBVIEW-UNION */
|
||||
platform = PLATFORMS.QUICKAPP_WEBVIEW_UNION;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef QUICKAPP-WEBVIEW-HUAWEI */
|
||||
platform = PLATFORMS.QUICKAPP_WEBVIEW_HUAWEI;
|
||||
/* #endif */
|
||||
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前平台
|
||||
* 在微信小程序中 "process.env['UNI_PLATFORM']" 无效
|
||||
*/
|
||||
export const CURRENT_PLATFORM = PLATFORM_ENV();
|
||||
31
src/enums/protocolsEnum.ts
Normal file
31
src/enums/protocolsEnum.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
[
|
||||
{"key":"userService","value":"用户服务协议"},
|
||||
{"key":"privacyPolicy","value":"个人信息保护政策"},
|
||||
{"key":"userPrivacy","value":"用户隐私政策"}
|
||||
{"key":"platformRules","value":"平台规则"},
|
||||
{"key":"platformQualification","value":"平台资质"}
|
||||
{"key":"personalInformation","value":"个人信息收集清单"},
|
||||
{"key":"thirdPartyInformation","value":"第三方信息共享清单"}
|
||||
]
|
||||
*/
|
||||
|
||||
export enum ProtocolsEnum {
|
||||
userService = '用户服务协议',
|
||||
privacyPolicy = '个人信息保护政策',
|
||||
userPrivacy = '用户隐私政策',
|
||||
platformRules = '平台规则',
|
||||
platformQualification = '平台资质',
|
||||
personalInformation = '个人信息收集清单',
|
||||
thirdPartyInformation = '第三方信息共享清单',
|
||||
}
|
||||
|
||||
export enum ProtocolsKey {
|
||||
userService = 'user_service',
|
||||
privacyPolicy = 'privacy_policy',
|
||||
userPrivacy = 'user_privacy',
|
||||
platformRules = 'platform_rules',
|
||||
platformQualification = 'platform_qualification',
|
||||
personalInformation = 'personal_information',
|
||||
thirdPartyInformation = 'third_party_information',
|
||||
}
|
||||
13
src/enums/routerEnum.ts
Normal file
13
src/enums/routerEnum.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export enum NAVIGATE_TYPE {
|
||||
NAVIGATE_TO = 'navigateTo',
|
||||
REDIRECT_TO = 'redirectTo',
|
||||
RE_LAUNCH = 'reLaunch',
|
||||
SWITCH_TAB = 'switchTab',
|
||||
NAVIGATE_BACK = 'navigateBack',
|
||||
}
|
||||
|
||||
export const NAVIGATE_TYPE_LIST = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'];
|
||||
|
||||
export const HOME_PAGE = '/pages/index/index';
|
||||
export const LOGIN_PAGE = '/pages/login/index';
|
||||
export const NOT_FOUND_PAGE = '/pages/notFound/404';
|
||||
14
src/layout/AppProvider.vue
Normal file
14
src/layout/AppProvider.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<!-- //@ts-nocheck -->
|
||||
<template>
|
||||
<view
|
||||
id="layout"
|
||||
:class="{
|
||||
dark: __themeModel === 'dark',
|
||||
}"
|
||||
class="bg-page flex flex-col"
|
||||
:style="__theme"
|
||||
style="min-height: 100vh; transition-duration: 1000ms; transition: all"
|
||||
>
|
||||
<!-- template -->
|
||||
</view>
|
||||
</template>
|
||||
18
src/mixins/theme.ts
Normal file
18
src/mixins/theme.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// 混入主题
|
||||
import { useSystemInfoStore } from '@/stores/modules/system';
|
||||
|
||||
export const themeMixin = {
|
||||
computed: {
|
||||
__themeModel() {
|
||||
const themeStore = storeToRefs(useSystemInfoStore());
|
||||
return themeStore.themeModel.value;
|
||||
},
|
||||
__theme() {
|
||||
const themeStore = storeToRefs(useSystemInfoStore());
|
||||
const theme = themeStore.theme.value;
|
||||
return Object.keys(theme)
|
||||
.map(key => `${key}:${theme[key]};`)
|
||||
.join('');
|
||||
},
|
||||
},
|
||||
};
|
||||
46
src/model/theme.ts
Normal file
46
src/model/theme.ts
Normal file
@ -0,0 +1,46 @@
|
||||
export interface ThemeCfg {
|
||||
'--colors-primary': string
|
||||
'--colors-secondary': string
|
||||
'--colors-accent': string
|
||||
'--colors-success': string
|
||||
'--colors-warning': string
|
||||
'--colors-error': string
|
||||
'--colors-disable': string
|
||||
'--colors-danger': string
|
||||
'--colors-mark': string
|
||||
'--colors-title': string
|
||||
'--colors-subtitle': string
|
||||
'--colors-paragraph': string
|
||||
'--colors-fontColorblack': string
|
||||
'--colors-fontColorPrimary': string
|
||||
'--colors-fontColorInverse': string
|
||||
'--colors-fontColorGrey': string
|
||||
'--colors-fontColorPlaceholder': string
|
||||
'--colors-fontColorDisable': string
|
||||
'--colors-fontColorBottomText': string
|
||||
'--colors-container': string
|
||||
'--colors-page': string
|
||||
'--colors-containerInverse': string
|
||||
'--colors-containerHover': string
|
||||
'--colors-containerMask': string
|
||||
'--colors-iconButton': string
|
||||
'--colors-borderColor': string
|
||||
'--fontSize-sm': string
|
||||
'--fontSize-base': string
|
||||
'--fontSize-lg': string
|
||||
'--fontSize-title': string
|
||||
'--fontSize-subtitle': string
|
||||
'--fontSize-paragraph': string
|
||||
'--borderRadius-sm': string
|
||||
'--borderRadius-base': string
|
||||
'--borderRadius-lg': string
|
||||
'--borderRadius-circle': string
|
||||
'--spacing-rowSm': string
|
||||
'--spacing-rowBase': string
|
||||
'--spacing-rowLg': string
|
||||
'--spacing-colSm': string
|
||||
'--spacing-colBase': string
|
||||
'--spacing-colLg': string
|
||||
'--opacity-disabled': string
|
||||
[propName: string]: string
|
||||
}
|
||||
47
src/stores/modules/system.ts
Normal file
47
src/stores/modules/system.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { THEME_MODEL } from '@/enums/UI';
|
||||
import type { ThemeCfg } from '@/model/theme';
|
||||
import { theme as _theme } from '@/theme/theme';
|
||||
|
||||
interface SystemInfo {
|
||||
theme: ThemeCfg
|
||||
themeModel: THEME_MODEL
|
||||
systemInfo: UniApp.GetSystemInfoResult
|
||||
}
|
||||
|
||||
export const useSystemInfoStore = defineStore({
|
||||
id: 'system',
|
||||
state: (): SystemInfo => ({
|
||||
// 主题
|
||||
// theme: <ThemeCfg>Object.assign(_theme.light),
|
||||
theme: <ThemeCfg>{ ..._theme.light },
|
||||
|
||||
// 当前主题模式
|
||||
themeModel: THEME_MODEL.LIGHT as THEME_MODEL,
|
||||
|
||||
// 系统信息
|
||||
systemInfo: {
|
||||
statusBarHeight: 0,
|
||||
} as UniApp.GetSystemInfoResult,
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
// 获取系统信息
|
||||
async getSystemInfo() {
|
||||
const res = (await uni.getSystemInfoSync()) as UniApp.GetSystemInfoResult;
|
||||
this.systemInfo = res;
|
||||
},
|
||||
|
||||
// 切换主题
|
||||
changeThemeModel({ model = THEME_MODEL.DARK as THEME_MODEL }) {
|
||||
this.themeModel = model;
|
||||
this.theme = { ..._theme[model] };
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
storage: {
|
||||
setItem: uni.setStorageSync,
|
||||
getItem: uni.getStorageSync,
|
||||
},
|
||||
paths: ['theme', 'themeModel', 'systemInfo'],
|
||||
},
|
||||
});
|
||||
205
src/theme/theme.ts
Normal file
205
src/theme/theme.ts
Normal file
@ -0,0 +1,205 @@
|
||||
/**
|
||||
* 主题根文件
|
||||
* @note 命名规则: ( key )
|
||||
* -- 变量标志符
|
||||
* colors 变量类型
|
||||
* primary 变量标识符
|
||||
* 在本文件的各种定义主题中 key 名应当保持完全统一
|
||||
* 按照此格式书写的 key 名完全路径禁止有重叠,否则会引发 bug
|
||||
*/
|
||||
// container {
|
||||
// // ThemeColor
|
||||
// '--source': '#00bdd4',
|
||||
// }
|
||||
|
||||
/**
|
||||
* secondary :通常用于表示次要的、补充的元素,例如按钮的边框颜色、图标的颜色等。
|
||||
* accent :通常用于表示强调的、突出的元素,例如链接的颜色、高亮的颜色等。
|
||||
* tertiary :通常用于表示第三级的、较为次要的元素,例如表格的边框颜色、分割线的颜色等。
|
||||
* neutral :通常用于表示中性的、不带有情感色彩的元素,例如背景色、文本颜色等。
|
||||
*/
|
||||
|
||||
export const theme = {
|
||||
light: {
|
||||
/* light */
|
||||
|
||||
/* 颜色 */
|
||||
'--colors-primary': '#FFE274', // 主色
|
||||
'--colors-secondary': '#5A7767', // 次要
|
||||
'--colors-accent': '#FB9300', // 强调
|
||||
|
||||
'--colors-success': '#4cd964',
|
||||
'--colors-warning': '#f0ad4e',
|
||||
'--colors-error': '#dd524d',
|
||||
'--colors-disable': '#ddd',
|
||||
'--colors-danger': '#FF6843',
|
||||
'--colors-mark': 'rgba(0,0,0,0.4)',
|
||||
|
||||
/* 文章场景相关 */
|
||||
'--colors-title': '#2c405a', // 文章标题颜色
|
||||
'--colors-subtitle': '#555555', // 二级标题颜色
|
||||
'--colors-paragraph': '#3f536e', // 文章段落颜色
|
||||
|
||||
/* 文字基本颜色 */
|
||||
'--colors-fontColorblack': '#333', // 基本色 - 不切换
|
||||
'--colors-fontColorPrimary': '#333', // 基本色
|
||||
'--colors-fontColorInverse': '#fff', // 反色
|
||||
'--colors-fontColorGrey': '#999', // 辅助灰色,如加载更多的提示信息
|
||||
'--colors-fontColorPlaceholder': '#808080',
|
||||
'--colors-fontColorDisable': '#c0c0c0',
|
||||
'--colors-fontColorBottomText': '#6F6E80', // 底部tabbar文字颜色
|
||||
|
||||
/* 背景颜色 */
|
||||
'--colors-container': '#ffffff',
|
||||
'--colors-page': '#F6F4F0',
|
||||
'--colors-containerInverse': '#000000', // 背景反色
|
||||
'--colors-containerHover': 'rgba(255, 226, 116, .5)', // 点击状态颜色
|
||||
'--colors-secondaryHover': 'rgba(90,119,103, .5)', // 点击状态颜色
|
||||
'--colors-containerMask': 'rgba(0, 0, 0, 0.4)', // 遮罩颜色
|
||||
// '--colors-iconButton': '#F5F5EC',
|
||||
'--colors-iconButton': '#E4E4E4', // ICON 按钮背景色
|
||||
|
||||
/* 边框颜色 */
|
||||
'--colors-borderColor': '#c8c7cc',
|
||||
|
||||
/* 文字尺寸 */
|
||||
'--fontSize-sm': '24rpx',
|
||||
'--fontSize-base': '28rpx',
|
||||
'--fontSize-lg': '32rpx',
|
||||
/* 文章场景相关 */
|
||||
'--fontSize-title': '40rpx',
|
||||
'--fontSize-subtitle': '36rpx',
|
||||
'--fontSize-paragraph': '32rpx',
|
||||
|
||||
/* Border Radius */
|
||||
'--borderRadius-sm': '4rpx',
|
||||
'--borderRadius-base': '6rpx',
|
||||
'--borderRadius-lg': '12rpx',
|
||||
'--borderRadius-circle': '50%',
|
||||
|
||||
/* 水平间距 */
|
||||
'--spacing-rowSm': '12px',
|
||||
'--spacing-rowBase': '24rpx',
|
||||
'--spacing-rowLg': '32rpx',
|
||||
|
||||
/* 垂直间距 */
|
||||
'--spacing-colSm': '8rpx',
|
||||
'--spacing-colBase': '16rpx',
|
||||
'--spacing-colLg': '24rpx',
|
||||
|
||||
/* 透明度 */
|
||||
'--opacity-disabled': '0.3', // 组件禁用态的透明度
|
||||
},
|
||||
dark: {
|
||||
/* dark */
|
||||
|
||||
/* 颜色 */
|
||||
'--colors-primary': '#FFE274',
|
||||
'--colors-secondary': '#5A7767', // 次要
|
||||
'--colors-accent': '#FB9300', // 强调
|
||||
|
||||
'--colors-success': '#4cd964',
|
||||
'--colors-warning': '#f0ad4e',
|
||||
'--colors-error': '#dd524d',
|
||||
'--colors-disable': '#ddd',
|
||||
'--colors-danger': '#FF6843',
|
||||
'--colors-mark': 'rgba(26, 26, 26,0.4)',
|
||||
|
||||
/* 文章场景相关 */
|
||||
'--colors-title': '#2c405a', // 文章标题颜色
|
||||
'--colors-subtitle': '#555555', // 二级标题颜色
|
||||
'--colors-paragraph': '#3f536e', // 文章段落颜色
|
||||
|
||||
/* 文字基本颜色 */
|
||||
'--colors-fontColorblack': '#333', // 基本色 - 不切换
|
||||
'--colors-fontColorPrimary': '#999', // 基本色
|
||||
'--colors-fontColorInverse': '#333', // 反色
|
||||
'--colors-fontColorGrey': '#666', // 辅助灰色,如加载更多的提示信息
|
||||
'--colors-fontColorPlaceholder': '#808080',
|
||||
'--colors-fontColorDisable': '#c0c0c0',
|
||||
'--colors-fontColorBottomText': '#6F6E80', // 底部tabbar文字颜色
|
||||
|
||||
/* 背景颜色 */
|
||||
'--colors-container': '#000000',
|
||||
'--colors-page': '#191919',
|
||||
'--colors-containerInverse': '#ffffff', // 背景反色
|
||||
'--colors-containerHover': 'rgba(255, 226, 116, .5)', // 点击状态颜色
|
||||
'--colors-secondaryHover': 'rgba(90,119,103, .5)', // 点击状态颜色
|
||||
'--colors-containerMask': 'rgba(0, 0, 0, 0.4)', // 遮罩颜色
|
||||
'--colors-iconButton': '#808080', // ICON 按钮背景色
|
||||
|
||||
/* 边框颜色 */
|
||||
'--colors-borderColor': '#c8c7cc',
|
||||
|
||||
/* 文字尺寸 */
|
||||
'--fontSize-sm': '24rpx',
|
||||
'--fontSize-base': '28rpx',
|
||||
'--fontSize-lg': '32rpx',
|
||||
|
||||
/* 文章场景相关 */
|
||||
'--fontSize-title': '40rpx',
|
||||
'--fontSize-subtitle': '36rpx',
|
||||
'--fontSize-paragraph': '32rpx',
|
||||
|
||||
/* Border Radius */
|
||||
'--borderRadius-sm': '4rpx',
|
||||
'--borderRadius-base': '6rpx',
|
||||
'--borderRadius-lg': '12rpx',
|
||||
'--borderRadius-circle': '50%',
|
||||
|
||||
/* 水平间距 */
|
||||
'--spacing-rowSm': '12px',
|
||||
'--spacing-rowBase': '24rpx',
|
||||
'--spacing-rowLg': '32rpx',
|
||||
|
||||
/* 垂直间距 */
|
||||
'--spacing-colSm': '8rpx',
|
||||
'--spacing-colBase': '16rpx',
|
||||
'--spacing-colLg': '24rpx',
|
||||
|
||||
/* 透明度 */
|
||||
'--opacity-disabled': '0.3', // 组件禁用态的透明度
|
||||
},
|
||||
};
|
||||
|
||||
enum ExtendStyle {
|
||||
SPACING = 'spacing',
|
||||
// BORDERRADIUS = 'borderRadius' ,
|
||||
// FONTSIZE = 'fontSize',
|
||||
OPACITY = 'opacity',
|
||||
}
|
||||
|
||||
// 构建 theme
|
||||
export function buildTheme() {
|
||||
const _theme: any = {
|
||||
extend: {},
|
||||
};
|
||||
|
||||
const flattenedObj: Map<string, any> = new Map([]);
|
||||
for (const [_, themeItem] of Object.entries(theme)) {
|
||||
for (const [key, _] of Object.entries(themeItem)) {
|
||||
flattenedObj.set(key, _);
|
||||
}
|
||||
}
|
||||
|
||||
const extendList = [ExtendStyle.OPACITY];
|
||||
|
||||
flattenedObj.forEach((_v: string, k: string) => {
|
||||
// const [_, key, value] = k.match(/^--(.+?)-(.+)$/) || [0, 'key', 'value'];
|
||||
const [_, key, value] = k.match(/^--([^-]+)-(.+)$/) || [0, 'key', 'value'];
|
||||
|
||||
if (extendList.includes(key as ExtendStyle)) {
|
||||
if (!_theme.extend[key]) {
|
||||
_theme.extend[key] = {};
|
||||
}
|
||||
_theme.extend[key][value] = `var(${k})`;
|
||||
} else {
|
||||
if (!_theme[key]) {
|
||||
_theme[key] = {};
|
||||
}
|
||||
_theme[key][value] = `var(${k})`;
|
||||
}
|
||||
});
|
||||
// console.log('_theme ===>>>', _theme);
|
||||
return _theme;
|
||||
}
|
||||
16
src/types/import-components.d.ts
vendored
Normal file
16
src/types/import-components.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AppProvider: typeof import('./../components/AppProvider/index.vue')['default']
|
||||
BasicButton: typeof import('./../components/BasicButton/index.vue')['default']
|
||||
BasicInput: typeof import('./../components/BasicInput/index.vue')['default']
|
||||
Iconify: typeof import('./../components/Iconify/index.vue')['default']
|
||||
Test: typeof import('./../components/Test/index.vue')['default']
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
import { getCache, setCache } from '@/utils/cache';
|
||||
import { TOKEN_KEY } from '@/enums/cacheEnum';
|
||||
|
||||
const authenticationScheme = 'Bearer';
|
||||
|
||||
export function getToken() {
|
||||
return getCache<string>(TOKEN_KEY) || null;
|
||||
}
|
||||
|
||||
export function getAuthorization() {
|
||||
const token = getToken();
|
||||
return token ? `${authenticationScheme} ${token}` : null;
|
||||
}
|
||||
|
||||
export function setToken(token: string) {
|
||||
return setCache(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return setCache(TOKEN_KEY, null);
|
||||
}
|
||||
|
||||
// 是否登录
|
||||
export function isLogin() {
|
||||
return !!getToken();
|
||||
}
|
||||
29
src/utils/cache/index.ts
vendored
29
src/utils/cache/index.ts
vendored
@ -1,29 +0,0 @@
|
||||
import type { CreateStorageParams } from './storageCache';
|
||||
import { createStorage } from './storageCache';
|
||||
import { DEFAULT_CACHE_TIME, DEFAULT_PREFIX_KEY, cacheCipher, enableStorageEncryption } from '@/settings/encryptionSetting';
|
||||
|
||||
const options: Partial<CreateStorageParams> = {
|
||||
prefixKey: DEFAULT_PREFIX_KEY,
|
||||
key: cacheCipher.key,
|
||||
iv: cacheCipher.iv,
|
||||
hasEncrypt: enableStorageEncryption,
|
||||
timeout: DEFAULT_CACHE_TIME,
|
||||
};
|
||||
|
||||
export const storage = createStorage(options);
|
||||
|
||||
export function setCache(key: string, value: any, expire?: number | null): void {
|
||||
storage.set(key, value, expire);
|
||||
}
|
||||
|
||||
export function getCache<T = any>(key: string): T {
|
||||
return storage.get<T>(key);
|
||||
}
|
||||
|
||||
export function removeCache(key: string): void {
|
||||
return storage.remove(key);
|
||||
}
|
||||
|
||||
export function clearCache(): void {
|
||||
return storage.clear();
|
||||
}
|
||||
110
src/utils/cache/storageCache.ts
vendored
110
src/utils/cache/storageCache.ts
vendored
@ -1,110 +0,0 @@
|
||||
import { cacheCipher } from '@/settings/encryptionSetting';
|
||||
import type { EncryptionParams } from '@/utils/cipher';
|
||||
import { AesEncryption } from '@/utils/cipher';
|
||||
import { isNullOrUnDef } from '@/utils/is';
|
||||
|
||||
export interface CreateStorageParams extends EncryptionParams {
|
||||
prefixKey: string
|
||||
hasEncrypt: boolean
|
||||
timeout?: number | null
|
||||
}
|
||||
export function createStorage({
|
||||
prefixKey = '',
|
||||
key = cacheCipher.key,
|
||||
iv = cacheCipher.iv,
|
||||
timeout = null,
|
||||
hasEncrypt = true,
|
||||
}: Partial<CreateStorageParams> = {}) {
|
||||
if (hasEncrypt && [key.length, iv.length].some(item => item !== 16)) {
|
||||
throw new Error('When hasEncrypt is true, the key or iv must be 16 bits!');
|
||||
}
|
||||
|
||||
const encryption = new AesEncryption({ key, iv });
|
||||
|
||||
/**
|
||||
* Cache class
|
||||
* Construction parameters can be passed into sessionStorage, localStorage,
|
||||
* @class Cache
|
||||
* @example
|
||||
*/
|
||||
class Storage {
|
||||
private prefixKey?: string;
|
||||
|
||||
private encryption: AesEncryption;
|
||||
|
||||
private hasEncrypt: boolean;
|
||||
|
||||
constructor() {
|
||||
this.prefixKey = prefixKey;
|
||||
this.encryption = encryption;
|
||||
this.hasEncrypt = hasEncrypt;
|
||||
}
|
||||
|
||||
private getKey(key: string) {
|
||||
return `${this.prefixKey}${key}`.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache
|
||||
* @param {string} key
|
||||
* @param {*} value
|
||||
* @param {*} expire Expiration time in seconds
|
||||
* @memberof Cache
|
||||
*/
|
||||
set(key: string, value: any, expire: number | null = timeout) {
|
||||
try {
|
||||
const stringData = JSON.stringify({
|
||||
value,
|
||||
time: Date.now(),
|
||||
expire: !isNullOrUnDef(expire) ? new Date().getTime() + expire * 1000 : null,
|
||||
});
|
||||
const stringifyValue = this.hasEncrypt ? this.encryption.encryptByAES(stringData) : stringData;
|
||||
uni.setStorageSync(this.getKey(key), stringifyValue);
|
||||
} catch (err) {
|
||||
throw new Error(`setStorageSync error: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read cache
|
||||
* @param {string} key
|
||||
* @param {*} def
|
||||
* @memberof Cache
|
||||
*/
|
||||
get<T = any>(key: string, def: any = null): T {
|
||||
const val = uni.getStorageSync(this.getKey(key));
|
||||
if (!val)
|
||||
return def;
|
||||
|
||||
try {
|
||||
const decVal = this.hasEncrypt ? this.encryption.decryptByAES(val) : val;
|
||||
const data = JSON.parse(decVal);
|
||||
const { value, expire } = data;
|
||||
if (isNullOrUnDef(expire) || expire < new Date().getTime()) {
|
||||
this.remove(key);
|
||||
return def;
|
||||
}
|
||||
return value;
|
||||
} catch (e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cache based on key
|
||||
* @param {string} key
|
||||
* @memberof Cache
|
||||
*/
|
||||
remove(key: string) {
|
||||
uni.removeStorageSync(this.getKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all caches of this instance
|
||||
*/
|
||||
clear(): void {
|
||||
uni.clearStorageSync();
|
||||
}
|
||||
}
|
||||
return new Storage();
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
/**
|
||||
* unocss defineConfig
|
||||
* @link unocss: https://github.com/unocss/unocss
|
||||
* @type {import('unocss').UserConfig}
|
||||
*/
|
||||
|
||||
import { defineConfig, presetIcons } from 'unocss';
|
||||
import presetWeapp from 'unocss-preset-weapp';
|
||||
import { transformerAttributify, transformerClass } from 'unocss-preset-weapp/transformer';
|
||||
|
||||
const transformRules = {
|
||||
'.': '-d2e-',
|
||||
'/': '-s2f-',
|
||||
':': '-c3a-',
|
||||
'%': '-p25-',
|
||||
'!': '-e21-',
|
||||
'#': '-w23-',
|
||||
'(': '-b28-',
|
||||
')': '-b29-',
|
||||
'[': '-f4b-',
|
||||
']': '-f5d-',
|
||||
'$': '-r24-',
|
||||
',': '-r2c-',
|
||||
};
|
||||
|
||||
const prefix = '';
|
||||
|
||||
export default defineConfig({
|
||||
presets: [
|
||||
// https://github.com/MellowCo/unocss-preset-weapp
|
||||
presetWeapp({
|
||||
nonValuedAttribute: true,
|
||||
prefix,
|
||||
whRpx: true,
|
||||
transform: true,
|
||||
platform: 'uniapp',
|
||||
transformRules,
|
||||
}),
|
||||
presetIcons({
|
||||
scale: 1.2,
|
||||
warn: true,
|
||||
}),
|
||||
],
|
||||
shortcuts: [
|
||||
{
|
||||
center: 'flex justify-center items-center',
|
||||
},
|
||||
],
|
||||
theme: {
|
||||
colors: {
|
||||
primary: '#007AFF',
|
||||
secondary: '#4CD964',
|
||||
danger: '#FF3B30',
|
||||
warning: '#FF9500',
|
||||
info: '#5AC8FA',
|
||||
light: '#F0F0F0',
|
||||
dark: '#1A1A1A',
|
||||
},
|
||||
fontSize: {
|
||||
mini: ['20rpx', '26rpx'],
|
||||
},
|
||||
},
|
||||
transformers: [
|
||||
transformerAttributify({
|
||||
classPrefix: prefix,
|
||||
transformRules,
|
||||
nonValuedAttribute: true,
|
||||
}),
|
||||
transformerClass({
|
||||
transformRules,
|
||||
}),
|
||||
],
|
||||
});
|
||||
97
unocss.config.ts
Normal file
97
unocss.config.ts
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* unocss defineConfig
|
||||
* @link unocss: https://github.com/unocss/unocss
|
||||
* @link unocss-preset-weapp: https://github.com/MellowCo/unocss-preset-weapp
|
||||
*/
|
||||
import presetWeapp from 'unocss-preset-weapp';
|
||||
import { extractorAttributify, transformerClass } from 'unocss-preset-weapp/transformer';
|
||||
import { presetIcons } from 'unocss';
|
||||
|
||||
import transformerDirectives from '@unocss/transformer-directives';
|
||||
|
||||
const { presetWeappAttributify, transformerAttributify } = extractorAttributify();
|
||||
|
||||
export default {
|
||||
presets: [
|
||||
// https://github.com/MellowCo/unocss-preset-weapp
|
||||
presetWeapp(),
|
||||
// attributify autocomplete
|
||||
presetWeappAttributify(),
|
||||
presetIcons(),
|
||||
],
|
||||
shortcuts: [
|
||||
{
|
||||
'border-base': 'border border-gray-500_10',
|
||||
'center': 'flex justify-center items-center',
|
||||
},
|
||||
],
|
||||
transformers: [
|
||||
transformerDirectives({
|
||||
enforce: 'pre',
|
||||
}),
|
||||
|
||||
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerAttributify
|
||||
transformerAttributify(),
|
||||
|
||||
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerClass
|
||||
transformerClass(),
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
opacity: {
|
||||
disabled: 'var(--opacity-disabled)',
|
||||
},
|
||||
},
|
||||
colors: {
|
||||
primary: 'var(--colors-primary)',
|
||||
secondary: 'var(--colors-secondary)',
|
||||
accent: 'var(--colors-accent)',
|
||||
success: 'var(--colors-success)',
|
||||
warning: 'var(--colors-warning)',
|
||||
error: 'var(--colors-error)',
|
||||
disable: 'var(--colors-disable)',
|
||||
danger: 'var(--colors-danger)',
|
||||
mark: 'var(--colors-mark)',
|
||||
title: 'var(--colors-title)',
|
||||
subtitle: 'var(--colors-subtitle)',
|
||||
paragraph: 'var(--colors-paragraph)',
|
||||
fontColorblack: 'var(--colors-fontColorblack)',
|
||||
fontColorPrimary: 'var(--colors-fontColorPrimary)',
|
||||
fontColorInverse: 'var(--colors-fontColorInverse)',
|
||||
fontColorGrey: 'var(--colors-fontColorGrey)',
|
||||
fontColorPlaceholder: 'var(--colors-fontColorPlaceholder)',
|
||||
fontColorDisable: 'var(--colors-fontColorDisable)',
|
||||
fontColorBottomText: 'var(--colors-fontColorBottomText)',
|
||||
container: 'var(--colors-container)',
|
||||
page: 'var(--colors-page)',
|
||||
containerInverse: 'var(--colors-containerInverse)',
|
||||
containerHover: 'var(--colors-containerHover)',
|
||||
secondaryHover: 'var(--colors-secondaryHover)',
|
||||
containerMask: 'var(--colors-containerMask)',
|
||||
iconButton: 'var(--colors-iconButton)',
|
||||
borderColor: 'var(--colors-borderColor)',
|
||||
},
|
||||
fontSize: {
|
||||
sm: 'var(--fontSize-sm)',
|
||||
base: 'var(--fontSize-base)',
|
||||
lg: 'var(--fontSize-lg)',
|
||||
title: 'var(--fontSize-title)',
|
||||
subtitle: 'var(--fontSize-subtitle)',
|
||||
paragraph: 'var(--fontSize-paragraph)',
|
||||
},
|
||||
borderRadius: {
|
||||
sm: 'var(--borderRadius-sm)',
|
||||
base: 'var(--borderRadius-base)',
|
||||
lg: 'var(--borderRadius-lg)',
|
||||
circle: 'var(--borderRadius-circle)',
|
||||
},
|
||||
spacing: {
|
||||
rowSm: 'var(--spacing-rowSm)',
|
||||
rowBase: 'var(--spacing-rowBase)',
|
||||
rowLg: 'var(--spacing-rowLg)',
|
||||
colSm: 'var(--spacing-colSm)',
|
||||
colBase: 'var(--spacing-colBase)',
|
||||
colLg: 'var(--spacing-colLg)',
|
||||
},
|
||||
},
|
||||
};
|
||||
57
vite/plugins/appProvider.ts
Normal file
57
vite/plugins/appProvider.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import * as fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import * as process from 'node:process';
|
||||
import normallize from 'normalize-path';
|
||||
import type { PluginOption } from 'vite';
|
||||
|
||||
// export const defaultPagesRE = /src[/\\]pages(.*)[/\\](.*)[/\\](.*)\.vue$/;
|
||||
export const defaultPagesRE = /src[/\\]pages([^/\\]*)[/\\]([^/\\]*)[/\\](.*)\.vue$/;
|
||||
|
||||
export interface Options {
|
||||
pagesRE: RegExp
|
||||
name: string
|
||||
configPath: string
|
||||
pluginName: string
|
||||
DEBUG: boolean
|
||||
}
|
||||
|
||||
export default function (options: Partial<Options> = {}) {
|
||||
const {
|
||||
pagesRE = defaultPagesRE,
|
||||
name = './src/layout/AppProvider.vue',
|
||||
pluginName = 'AppProvider',
|
||||
// DEBUG = process.env.DEBUG,
|
||||
} = options;
|
||||
|
||||
const template = fs.readFileSync(normalizePagePathFromBase(name), 'utf-8');
|
||||
|
||||
return <PluginOption>{
|
||||
name: pluginName,
|
||||
enforce: 'pre',
|
||||
transform(code, id) {
|
||||
id = normalizePagePathFromBase(id);
|
||||
const regResult = pagesRE.exec(id);
|
||||
if (regResult && (regResult[2] === regResult[3] || regResult[3] === 'index')) {
|
||||
const oldTempleate = /<template>([\s\S]*)<\/template>/.exec(code);
|
||||
const tmp_string = oldTempleate != null ? oldTempleate[1] : '';
|
||||
const newTemplate = template.replace('<!-- template -->', tmp_string as string);
|
||||
code = code.replace(/<template>([\s\S]*)<\/template>/, newTemplate);
|
||||
}
|
||||
return { code, map: null };
|
||||
},
|
||||
};
|
||||
|
||||
function normalizePagePathFromBase(file: string) {
|
||||
return normallize(path.relative(process.cwd(), file));
|
||||
}
|
||||
|
||||
// function debug(...args) {
|
||||
// DEBUG &&
|
||||
// console.log(
|
||||
// c.dim(new Date().toLocaleTimeString()),
|
||||
// c.bold(c.red(`[debug:${pluginName}]`)),
|
||||
// ...args,
|
||||
// )
|
||||
// }
|
||||
}
|
||||
82
vite/plugins/build.unocss.config.ts
Normal file
82
vite/plugins/build.unocss.config.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import * as fs from 'node:fs';
|
||||
import { buildTheme } from '../../src/theme/theme';
|
||||
|
||||
export default function buildThemeConfig() {
|
||||
const _data = buildTheme();
|
||||
// 写入时会先清空文件
|
||||
fs.writeFile('./unocss.config.ts', `${createFileByTemplate(_data)}`, (err: any) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('构建 css 提示文件完成');
|
||||
console.table(flatten(_data));
|
||||
}
|
||||
});
|
||||
|
||||
// 写完文件后使用编辑器格式化一下
|
||||
}
|
||||
|
||||
function flatten(obj: any, parentKey = ''): any {
|
||||
let result: any = {};
|
||||
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const newKey = parentKey ? `${parentKey}.${key}` : key;
|
||||
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
const flattened = flatten(value, newKey);
|
||||
result = { ...result, ...flattened };
|
||||
} else {
|
||||
result[newKey] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 通过模版生成文件
|
||||
function createFileByTemplate(theme: any) {
|
||||
const fileString = `
|
||||
/**
|
||||
* unocss defineConfig
|
||||
* @link unocss: https://github.com/unocss/unocss
|
||||
* @link unocss-preset-weapp: https://github.com/MellowCo/unocss-preset-weapp
|
||||
* */
|
||||
import presetWeapp from 'unocss-preset-weapp'
|
||||
import { extractorAttributify, transformerClass } from 'unocss-preset-weapp/transformer'
|
||||
import { presetIcons } from 'unocss'
|
||||
|
||||
import transformerDirectives from '@unocss/transformer-directives'
|
||||
|
||||
const { presetWeappAttributify, transformerAttributify } = extractorAttributify()
|
||||
|
||||
export default {
|
||||
presets: [
|
||||
// https://github.com/MellowCo/unocss-preset-weapp
|
||||
presetWeapp(),
|
||||
// attributify autocomplete
|
||||
presetWeappAttributify(),
|
||||
presetIcons(),
|
||||
],
|
||||
shortcuts: [
|
||||
{
|
||||
'border-base': 'border border-gray-500_10',
|
||||
'center': 'flex justify-center items-center',
|
||||
},
|
||||
],
|
||||
transformers: [
|
||||
transformerDirectives({
|
||||
enforce: 'pre',
|
||||
}),
|
||||
|
||||
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerAttributify
|
||||
transformerAttributify(),
|
||||
|
||||
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerClass
|
||||
transformerClass(),
|
||||
],
|
||||
theme: ${JSON.stringify(theme, null, 2)}
|
||||
}
|
||||
`;
|
||||
|
||||
return fileString;
|
||||
}
|
||||
16
vite/plugins/components.ts
Normal file
16
vite/plugins/components.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type { Options } from 'unplugin-vue-components/types';
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
|
||||
export default function createComponents(options?: Options | undefined) {
|
||||
return Components({
|
||||
// 指定组件位置,默认是src/components
|
||||
dirs: ['src/components'],
|
||||
deep: true, // search for subdirectories
|
||||
// ui库解析器
|
||||
// resolvers: [ElementPlusResolver()],
|
||||
extensions: ['vue'],
|
||||
// 配置文件生成位置
|
||||
dts: 'src/types/import-components.d.ts',
|
||||
...options,
|
||||
});
|
||||
}
|
||||
5
vite/plugins/index.ts
Normal file
5
vite/plugins/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import appProvider from './appProvider';
|
||||
import buildThemeConfig from './build.unocss.config';
|
||||
import createComponents from './components';
|
||||
|
||||
export { appProvider, buildThemeConfig, createComponents };
|
||||
Loading…
x
Reference in New Issue
Block a user