mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-26 14:23:48 +00:00
feat: 初始化前端项目基础结构
- 添加项目配置文件(tsconfig, eslint, prettier等) - 实现基础路由和页面布局 - 添加全局状态管理和API请求封装 - 集成UI组件库和主题系统 - 添加文档网站和示例页面 - 配置CI/CD和工作流
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'about',
|
||||
style: {
|
||||
navigationBarTitleText: '关于',
|
||||
},
|
||||
})
|
||||
|
||||
// 核心团队成员
|
||||
const coreTeam = [
|
||||
{
|
||||
name: '不如摸鱼去',
|
||||
avatar: 'https://avatars.githubusercontent.com/u/26426873?v=4',
|
||||
role: '前端打工仔',
|
||||
desc: '负责WotUI组件库的开发和维护',
|
||||
github: 'https://github.com/Moonofweisheng',
|
||||
},
|
||||
{
|
||||
name: '二狗',
|
||||
avatar: 'https://avatars.githubusercontent.com/u/50100966?v=4',
|
||||
role: '灵活就业大师',
|
||||
desc: '问题毁灭者,总能迅速解决各种技术难题',
|
||||
github: 'https://github.com/810505339',
|
||||
},
|
||||
{
|
||||
name: 'RJQingHuan',
|
||||
avatar: 'https://avatars.githubusercontent.com/u/53939074?v=4',
|
||||
role: 'Pull Shark',
|
||||
desc: '热衷参与开源组件建设',
|
||||
github: 'https://github.com/RJQingHuan',
|
||||
},
|
||||
{
|
||||
name: 'skiyee',
|
||||
avatar: 'https://avatars.githubusercontent.com/u/120664167?v=4',
|
||||
role: 'uni-ku 的创立者,重金雇佣兵',
|
||||
desc: '精通 JS 和 TS 的全能攻城狮',
|
||||
github: 'https://github.com/skiyee',
|
||||
},
|
||||
{
|
||||
name: 'jasper-ops',
|
||||
avatar: 'https://avatars.githubusercontent.com/u/85024227?v=4',
|
||||
role: '新技术狂热分子',
|
||||
desc: '始终走在技术前沿,热衷于探索最新的开发趋势',
|
||||
github: 'https://github.com/jasper-ops',
|
||||
},
|
||||
]
|
||||
|
||||
function openUrl(url: string) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
// 打开公众号二维码
|
||||
function openWeChat() {
|
||||
uni.previewImage({
|
||||
urls: ['https://wot-ui.cn/wechatPublicAccount.png'],
|
||||
})
|
||||
}
|
||||
|
||||
// 打开捐赠二维码
|
||||
function donate() {
|
||||
uni.previewImage({
|
||||
urls: ['https://wot-ui.cn/weixinQrcode.jpg'],
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3 flex flex-col gap-2">
|
||||
<text class="text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
关于我们
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]">
|
||||
我是不如摸鱼去,一个前端打工仔,我和我的小伙伴们正在致力于开发轻量、高效的uni-app组件库和高效、易用的uni-app快速开发模板。
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 核心团队 -->
|
||||
<demo-block title="核心团队" transparent>
|
||||
<view class="grid grid-cols-2 gap-3">
|
||||
<view
|
||||
v-for="member in coreTeam"
|
||||
:key="member.name"
|
||||
class="rounded-2 bg-white p-4 text-center dark:bg-[var(--wot-dark-background2)]"
|
||||
@click="openUrl(member.github)"
|
||||
>
|
||||
<image
|
||||
:src="member.avatar"
|
||||
class="mx-auto mb-2 h-16 w-16 border-2 border-blue-200 rounded-full dark:border-blue-800"
|
||||
/>
|
||||
<view class="mb-1 text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ member.name }}
|
||||
</view>
|
||||
<view class="mb-2 text-2.5 text-blue-600 dark:text-blue-400">
|
||||
{{ member.role }}
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]">
|
||||
{{ member.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 关于 uni-helper -->
|
||||
<demo-block title="关于 uni-helper 团队" transparent>
|
||||
<view class="rounded-3 bg-white p-5 dark:bg-[var(--wot-dark-background2)]">
|
||||
<text class="mb-3 block text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
<text class="text-blue-600" @click="openUrl('https://uni-helper.cn/')">
|
||||
uni-helper
|
||||
</text>
|
||||
是一个旨在增强 uni-app 系列产品的开发体验为爱发电的非官方组织。作为靠爱发电的非官方项目,uni-helper 提供了打包工具插件支持、编辑器扩展支持、NPM 包等并尽力维护它们。
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
在此我们特别向 uni-helper 团队表示感谢,他们为 uni-app 系列产品提供了强大的支持,包括打包工具插件支持、编辑器扩展支持等,这使我们得以站在巨人的巨人的肩膀上完成此项目。
|
||||
</text>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 更多信息 -->
|
||||
<demo-block title="更多信息" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell
|
||||
title="关注公众号"
|
||||
title-width="200px"
|
||||
label="uni-app教程、组件库讯息一手掌握!"
|
||||
is-link
|
||||
@click="openWeChat"
|
||||
/>
|
||||
<wd-cell
|
||||
title="捐赠"
|
||||
title-width="200px"
|
||||
label="每一份捐赠都是对我们莫大的鼓励!"
|
||||
is-link
|
||||
@click="donate"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,225 @@
|
||||
<script setup lang="ts">
|
||||
import type { PasswordChangeForm, UserInfo } from '@/api/user'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import UserAPI from '@/api/user'
|
||||
|
||||
definePage({
|
||||
name: 'account',
|
||||
style: {
|
||||
navigationBarTitleText: '账号设置',
|
||||
},
|
||||
})
|
||||
|
||||
const userProfile = ref<UserInfo>() // 用户信息
|
||||
const passwordChangeForm = reactive<PasswordChangeForm>({
|
||||
old_password: '',
|
||||
new_password: '',
|
||||
confirm_password: '',
|
||||
})
|
||||
const passwordChangeFormRef = ref()
|
||||
|
||||
// 本页面中所有的校验规则
|
||||
const rules = reactive({
|
||||
oldPassword: [{ required: true, message: '请填写原密码' }],
|
||||
newPassword: [{ required: true, message: '请填写新密码' }],
|
||||
confirmPassword: [
|
||||
{
|
||||
required: true,
|
||||
message: '请确认密码',
|
||||
validator: (value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject(new Error('请确认密码'))
|
||||
}
|
||||
else {
|
||||
if (value !== passwordChangeForm.new_password) {
|
||||
return Promise.reject(new Error('两次输入的密码不一致'))
|
||||
}
|
||||
else {
|
||||
return Promise.resolve()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: '请填写正确的手机号码',
|
||||
},
|
||||
],
|
||||
code: [{ required: true, message: '请填写验证码' }],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
pattern: /\w[-\w.+]*@([A-Z0-9][-A-Z0-9]+\.)+[A-Z]{2,14}/i,
|
||||
message: '请填写正确的邮箱地址',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
enum DialogType {
|
||||
PASSWORD = 'password',
|
||||
MOBILE = 'mobile',
|
||||
EMAIL = 'email',
|
||||
}
|
||||
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
type: '' as DialogType,
|
||||
})
|
||||
|
||||
const getDialogTitle = computed(() => {
|
||||
switch (dialog?.type) {
|
||||
case DialogType.PASSWORD:
|
||||
return '修改密码'
|
||||
case DialogType.MOBILE:
|
||||
return '绑定手机'
|
||||
case DialogType.EMAIL:
|
||||
return '绑定邮箱'
|
||||
default:
|
||||
return '账号设置'
|
||||
}
|
||||
})
|
||||
|
||||
async function loadUserProfile() {
|
||||
userProfile.value = await UserAPI.getCurrentUserInfo()
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
* @param type 弹窗类型 ACCOUNT: 账号资料 PASSWORD: 修改密码 MOBILE: 绑定手机 EMAIL: 绑定邮箱
|
||||
*/
|
||||
function handleOpenDialog(type: DialogType) {
|
||||
dialog.type = type
|
||||
dialog.visible = true
|
||||
switch (type) {
|
||||
case DialogType.PASSWORD:
|
||||
passwordChangeForm.old_password = ''
|
||||
passwordChangeForm.new_password = ''
|
||||
passwordChangeForm.confirm_password = ''
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
function handleSubmit() {
|
||||
if (dialog.type === DialogType.PASSWORD) {
|
||||
passwordChangeFormRef.value
|
||||
.validate()
|
||||
.then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.changeCurrentUserPassword(passwordChangeForm)
|
||||
.then(() => {
|
||||
uni.showToast({ title: '密码修改成功', icon: 'success' })
|
||||
dialog.visible = false
|
||||
})
|
||||
.catch((error: any) => {
|
||||
uni.showToast({
|
||||
title: error?.message || '密码修改失败',
|
||||
icon: 'error',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadUserProfile()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="app-container">
|
||||
<wd-card custom-style="margin-top: 20rpx" class="theme-card">
|
||||
<wd-cell-group border>
|
||||
<wd-cell
|
||||
title="账户密码"
|
||||
label="定期修改密码有助于保护账户安全"
|
||||
value="修改"
|
||||
is-link
|
||||
@click="handleOpenDialog(DialogType.PASSWORD)"
|
||||
>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
账户密码
|
||||
</text>
|
||||
</template>
|
||||
<template #label>
|
||||
<text class="theme-text-secondary">
|
||||
定期修改密码有助于保护账户安全
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
修改
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</wd-card>
|
||||
|
||||
<!-- 用户信息编辑弹出框 -->
|
||||
<wd-popup
|
||||
v-model="dialog.visible"
|
||||
position="bottom"
|
||||
custom-style="border-top-left-radius: 16rpx; border-top-right-radius: 16rpx;"
|
||||
>
|
||||
<view class="popup-header">
|
||||
<wd-cell :title="getDialogTitle" center>
|
||||
<template #right-icon>
|
||||
<wd-icon name="close" size="20" @click="dialog.visible = false" />
|
||||
</template>
|
||||
</wd-cell>
|
||||
</view>
|
||||
|
||||
<wd-divider />
|
||||
|
||||
<wd-form
|
||||
v-if="dialog.type === DialogType.PASSWORD"
|
||||
ref="passwordChangeFormRef"
|
||||
:model="passwordChangeForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.old_password"
|
||||
label="原密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入原密码"
|
||||
prop="old_password"
|
||||
:rules="rules.oldPassword"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.new_password"
|
||||
label="新密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请输入新密码"
|
||||
prop="new_password"
|
||||
:rules="rules.newPassword"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="passwordChangeForm.confirm_password"
|
||||
label="确认密码"
|
||||
label-width="160rpx"
|
||||
show-password
|
||||
clearable
|
||||
placeholder="请确认新密码"
|
||||
prop="confirm_password"
|
||||
:rules="rules.confirmPassword"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
<view class="p-6">
|
||||
<wd-button type="primary" size="large" block @click="handleSubmit">
|
||||
提交
|
||||
</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import BarChart from '@/subPages/echarts/components/BarChart.vue'
|
||||
import DonutChart from '@/subPages/echarts/components/DonutChart.vue'
|
||||
import FunnelChart from '@/subPages/echarts/components/FunnelChart.vue'
|
||||
import GaugeChart from '@/subPages/echarts/components/GaugeChart.vue'
|
||||
import LineChart from '@/subPages/echarts/components/LineChart.vue'
|
||||
import LiquidFillChart from '@/subPages/echarts/components/LiquidFillChart.vue'
|
||||
import MiniLineChart from '@/subPages/echarts/components/MiniLineChart.vue'
|
||||
import PieChart from '@/subPages/echarts/components/PieChart.vue'
|
||||
import RadarChart from '@/subPages/echarts/components/RadarChart.vue'
|
||||
import ScatterChart from '@/subPages/echarts/components/ScatterChart.vue'
|
||||
import StackedBarChart from '@/subPages/echarts/components/StackedBarChart.vue'
|
||||
|
||||
defineOptions({
|
||||
componentPlaceholder: {
|
||||
BarChart: 'view',
|
||||
DonutChart: 'view',
|
||||
FunnelChart: 'view',
|
||||
GaugeChart: 'view',
|
||||
LineChart: 'view',
|
||||
LiquidFillChart: 'view',
|
||||
MiniLineChart: 'view',
|
||||
PieChart: 'view',
|
||||
RadarChart: 'view',
|
||||
ScatterChart: 'view',
|
||||
StackedBarChart: 'view',
|
||||
},
|
||||
})
|
||||
|
||||
definePage({
|
||||
name: 'echartsAsync',
|
||||
style: {
|
||||
navigationBarTitleText: 'echarts 异步跨包示例',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-gray-50 p-5">
|
||||
<!-- 饼图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
饼图示例
|
||||
</view>
|
||||
<PieChart />
|
||||
</view>
|
||||
|
||||
<!-- 柱状图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
柱状图示例
|
||||
</view>
|
||||
<BarChart />
|
||||
</view>
|
||||
|
||||
<!-- 折线图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
折线图示例
|
||||
</view>
|
||||
<LineChart />
|
||||
</view>
|
||||
|
||||
<!-- 雷达图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
雷达图示例
|
||||
</view>
|
||||
<RadarChart />
|
||||
</view>
|
||||
|
||||
<!-- 散点图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
散点图示例
|
||||
</view>
|
||||
<ScatterChart />
|
||||
</view>
|
||||
|
||||
<!-- 环形图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
环形图示例
|
||||
</view>
|
||||
<DonutChart />
|
||||
</view>
|
||||
|
||||
<!-- 漏斗图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
漏斗图示例
|
||||
</view>
|
||||
<FunnelChart />
|
||||
</view>
|
||||
|
||||
<!-- 仪表盘图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
仪表盘示例
|
||||
</view>
|
||||
<GaugeChart />
|
||||
</view>
|
||||
|
||||
<!-- 迷你折线图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
迷你折线图示例
|
||||
</view>
|
||||
<MiniLineChart />
|
||||
</view>
|
||||
|
||||
<!-- 堆叠柱状图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
堆叠柱状图示例
|
||||
</view>
|
||||
<StackedBarChart />
|
||||
</view>
|
||||
|
||||
<!-- 水球图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
水球图示例
|
||||
</view>
|
||||
<LiquidFillChart />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,428 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'ci',
|
||||
style: {
|
||||
navigationBarTitleText: 'CI 持续集成',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
|
||||
// 配置示例数据
|
||||
const configExample = ref(`{
|
||||
"weixin": {
|
||||
"appid": "微信小程序appid",
|
||||
"privateKeyPath": "key/private.appid.key",
|
||||
"projectPath": "dist/build/mp-weixin"
|
||||
},
|
||||
"alipay": {
|
||||
"appid": "支付宝小程序appid",
|
||||
"toolId": "支付宝开放平台工具ID",
|
||||
"privateKey": "私钥文本内容",
|
||||
"projectPath": "dist/build/mp-alipay",
|
||||
"autoincrement": true
|
||||
},
|
||||
"dd": {
|
||||
"appid": "钉钉小程序appid",
|
||||
"token": "钉钉开发者后台的 API Token",
|
||||
"projectPath": "dist/build/mp-alipay",
|
||||
"autoincrement": true
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"desc": "版本描述"
|
||||
}`)
|
||||
|
||||
const packageScripts = ref(`{
|
||||
"scripts": {
|
||||
"upload:weixin": "minici --platform weixin",
|
||||
"upload:alipay": "minici --platform alipay",
|
||||
"upload:dd": "minici --platform dd",
|
||||
"upload:mp-weixin": "uni build -p mp-weixin && minici --platform weixin",
|
||||
"upload:mp-alipay": "uni build -p mp-alipay && minici --platform alipay",
|
||||
"upload:mp-dingtalk": "uni build -p mp-dingtalk && minici --platform dd"
|
||||
}
|
||||
}`)
|
||||
|
||||
// 特性列表
|
||||
const features = ref([
|
||||
{
|
||||
icon: '📱',
|
||||
title: '多平台支持',
|
||||
desc: '支持微信、支付宝、钉钉小程序的上传',
|
||||
},
|
||||
{
|
||||
icon: '🔢',
|
||||
title: '版本管理',
|
||||
desc: '支持指定版本号和版本号自增',
|
||||
},
|
||||
{
|
||||
icon: '⚙️',
|
||||
title: '简单配置',
|
||||
desc: '通过配置文件轻松管理多平台参数',
|
||||
},
|
||||
{
|
||||
icon: '🔄',
|
||||
title: 'CI/CD集成',
|
||||
desc: '完美集成持续集成和持续部署流程',
|
||||
},
|
||||
{
|
||||
icon: '🛠️',
|
||||
title: '命令行工具',
|
||||
desc: '支持全局和局部安装,灵活使用',
|
||||
},
|
||||
{
|
||||
icon: '📦',
|
||||
title: '打包上传',
|
||||
desc: '支持打包和上传命令组合使用',
|
||||
},
|
||||
])
|
||||
|
||||
// 平台配置
|
||||
const platforms = ref([
|
||||
{
|
||||
name: 'weixin',
|
||||
title: '微信小程序',
|
||||
icon: '💚',
|
||||
color: 'text-green-600',
|
||||
bgColor: 'bg-green-50',
|
||||
borderColor: 'border-green-200',
|
||||
features: ['支持企业微信', 'CI机器人选择', '编译设置', '代码压缩保护'],
|
||||
},
|
||||
{
|
||||
name: 'alipay',
|
||||
title: '支付宝小程序',
|
||||
icon: '💙',
|
||||
color: 'text-blue-600',
|
||||
bgColor: 'bg-blue-50',
|
||||
borderColor: 'border-blue-200',
|
||||
features: ['多终端支持', '版本号自增', '私钥认证', '开放平台集成'],
|
||||
},
|
||||
{
|
||||
name: 'dd',
|
||||
title: '钉钉小程序',
|
||||
icon: '💜',
|
||||
color: 'text-purple-600',
|
||||
bgColor: 'bg-purple-50',
|
||||
borderColor: 'border-purple-200',
|
||||
features: ['企业应用', '版本号自增', 'Token认证', '多应用类型'],
|
||||
},
|
||||
])
|
||||
|
||||
// 复制代码到剪贴板
|
||||
function copyCode(code: string) {
|
||||
uni.setClipboardData({
|
||||
data: code,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: '代码已复制到剪贴板' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: `${url} 已复制到剪贴板` })
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🚀
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
uni-mini-ci
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
小程序持续集成的插件
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
支持上传微信、企业微信、钉钉、支付宝平台的小程序
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心特性 -->
|
||||
<demo-block title="核心特性" transparent>
|
||||
<view class="grid grid-cols-2 gap-3">
|
||||
<view
|
||||
v-for="feature in features"
|
||||
:key="feature.title"
|
||||
class="rounded-2 bg-white p-4 text-center dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-2 text-6">
|
||||
{{ feature.icon }}
|
||||
</view>
|
||||
<view class="mb-1 text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ feature.title }}
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]">
|
||||
{{ feature.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 安装方式 -->
|
||||
<demo-block title="安装方式" transparent>
|
||||
<view class="space-y-4">
|
||||
<!-- 全局安装 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
全局安装
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
推荐在开发环境中全局安装,方便在任何项目中使用
|
||||
</view>
|
||||
<view class="space-y-2">
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('npm i uni-mini-ci -g')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
npm i uni-mini-ci -g
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 局部安装 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
局部安装
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
在项目中作为开发依赖安装,适合团队协作
|
||||
</view>
|
||||
<view class="space-y-2">
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('npm i uni-mini-ci --save-dev')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
npm i uni-mini-ci --save-dev
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('pnpm add uni-mini-ci -D')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
pnpm add uni-mini-ci -D
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 配置文件 -->
|
||||
<demo-block title="配置文件" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
.minicirc 配置文件
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
在项目根目录创建 <text class="rounded bg-gray-100 px-1 font-mono dark:bg-[var(--wot-dark-background3)]">
|
||||
.minicirc
|
||||
</text> 文件,配置各平台的上传参数
|
||||
</view>
|
||||
|
||||
<view class="mb-3 border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode(configExample)">
|
||||
<view class="mb-2 flex items-center justify-between">
|
||||
<text class="text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
配置示例:
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="max-h-60 overflow-y-auto">
|
||||
<pre class="whitespace-pre-wrap text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">{{ configExample }}</pre>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="border border-orange-200 rounded-2 bg-orange-50 p-3 dark:bg-orange-900/20">
|
||||
<view class="mb-2 text-3.5 text-orange-700 font-bold dark:text-orange-300">
|
||||
💡 配置说明
|
||||
</view>
|
||||
<view class="text-3 text-orange-600 leading-relaxed space-y-1 dark:text-orange-200">
|
||||
<view>• version: 上传版本号,不传时默认读取 package.json 的 version 字段</view>
|
||||
<view>• desc: 上传时的描述信息</view>
|
||||
<view>• autoincrement: 版本号自增,建议测试环境开启</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 支持平台 -->
|
||||
<demo-block title="支持平台" transparent>
|
||||
<view class="space-y-3">
|
||||
<view
|
||||
v-for="platform in platforms"
|
||||
:key="platform.name"
|
||||
class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
{{ platform.icon }}
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ platform.title }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="grid grid-cols-2 mb-3 gap-2">
|
||||
<view
|
||||
v-for="feature in platform.features"
|
||||
:key="feature"
|
||||
class="rounded bg-gray-100 px-2 py-1 text-center text-2.5 text-gray-600 dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]"
|
||||
>
|
||||
{{ feature }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode(`minici --platform ${platform.name}`)">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
minici --platform {{ platform.name }}
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 添加命令 -->
|
||||
<demo-block title="添加命令" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
package.json 脚本配置
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
在 package.json 中添加上传脚本,支持单独上传和打包上传组合
|
||||
</view>
|
||||
|
||||
<view class="mb-3 border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode(packageScripts)">
|
||||
<view class="mb-2 flex items-center justify-between">
|
||||
<text class="text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
脚本配置:
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="max-h-60 overflow-y-auto">
|
||||
<pre class="whitespace-pre-wrap text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">{{ packageScripts }}</pre>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="space-y-2">
|
||||
<view class="text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
使用命令:
|
||||
</view>
|
||||
<view class="grid grid-cols-1 gap-2">
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('pnpm upload:weixin')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
pnpm upload:weixin
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('pnpm upload:mp-weixin')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
pnpm upload:mp-weixin
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 使用步骤 -->
|
||||
<demo-block title="使用步骤" transparent>
|
||||
<view class="space-y-3">
|
||||
<view
|
||||
v-for="(step, index) in [
|
||||
{ title: '安装插件', desc: '选择全局或局部安装方式', icon: '📦' },
|
||||
{ title: '创建配置', desc: '在根目录创建 .minicirc 配置文件', icon: '⚙️' },
|
||||
{ title: '配置平台', desc: '填写各平台的 appid、密钥等信息', icon: '🔑' },
|
||||
{ title: '添加脚本', desc: '在 package.json 中添加上传命令', icon: '📝' },
|
||||
{ title: '执行上传', desc: '运行命令上传到对应平台', icon: '🚀' },
|
||||
]"
|
||||
:key="index"
|
||||
class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="flex items-center">
|
||||
<view class="mr-3 h-8 w-8 flex items-center justify-center rounded-full bg-blue-100 text-3.5 text-blue-600 font-bold dark:bg-blue-900/20 dark:text-blue-400">
|
||||
{{ index + 1 }}
|
||||
</view>
|
||||
<view class="mr-2 text-5">
|
||||
{{ step.icon }}
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<view class="text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ step.title }}
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
{{ step.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 注意事项 -->
|
||||
<demo-block title="注意事项" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="border border-red-200 rounded-2 bg-red-50 p-4 dark:bg-red-900/20">
|
||||
<view class="mb-2 text-3.5 text-red-700 font-bold dark:text-red-300">
|
||||
⚠️ 版本号限制
|
||||
</view>
|
||||
<view class="text-3 text-red-600 leading-relaxed dark:text-red-200">
|
||||
支付宝和钉钉小程序不支持上传的版本号小于或等于现有版本号。建议测试环境开启 autoincrement 字段,生产环境手动指定版本号。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="border border-blue-200 rounded-2 bg-blue-50 p-4 dark:bg-blue-900/20">
|
||||
<view class="mb-2 text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
💡 最佳实践
|
||||
</view>
|
||||
<view class="text-3 text-blue-600 leading-relaxed space-y-1 dark:text-blue-200">
|
||||
<view>• 测试环境:开启版本号自增,频繁调试更方便</view>
|
||||
<view>• 生产环境:手动指定版本号,便于版本管理</view>
|
||||
<view>• 密钥安全:不要将私钥文件提交到代码仓库</view>
|
||||
<view>• CI/CD:结合打包命令,实现自动化部署</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="border border-green-200 rounded-2 bg-green-50 p-4 dark:bg-green-900/20">
|
||||
<view class="mb-2 text-3.5 text-green-700 font-bold dark:text-green-300">
|
||||
🔒 安全建议
|
||||
</view>
|
||||
<view class="text-3 text-green-600 leading-relaxed space-y-1 dark:text-green-200">
|
||||
<view>• 使用环境变量存储敏感信息</view>
|
||||
<view>• 将配置文件添加到 .gitignore</view>
|
||||
<view>• 定期更换密钥和 Token</view>
|
||||
<view>• 限制 CI 机器人权限范围</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📦 NPM 包" value="uni-mini-ci" is-link @click="handleNavigate('https://www.npmjs.com/package/uni-mini-ci')" />
|
||||
<wd-cell title="🐙 GitHub 仓库" value="源码仓库" is-link @click="handleNavigate('https://github.com/Moonofweisheng/uni-mini-ci')" />
|
||||
<wd-cell title="📱 微信小程序 CI" value="官方文档" is-link @click="handleNavigate('https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html')" />
|
||||
<wd-cell title="💙 支付宝小程序 CI" value="官方文档" is-link @click="handleNavigate('https://opendocs.alipay.com/mini/02q29z')" />
|
||||
<wd-cell title="💜 钉钉小程序 CI" value="官方文档" is-link @click="handleNavigate('https://github.com/open-dingtalk/dingtalk-design-cli')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,252 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'create-uni',
|
||||
style: {
|
||||
navigationBarTitleText: 'CreateUni 脚手架',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
// 核心优势
|
||||
const advantages = ref([
|
||||
{
|
||||
icon: '🚀',
|
||||
title: '简单易用',
|
||||
desc: '一行命令即可创建项目,无需手动配置开发环境',
|
||||
},
|
||||
{
|
||||
icon: '🔧',
|
||||
title: '功能强大',
|
||||
desc: '内置多种实用工具和插件,支持一键集成 WotUI',
|
||||
},
|
||||
{
|
||||
icon: '🔄',
|
||||
title: '持续更新',
|
||||
desc: '由 uni-helper 团队积极维护,及时跟进最新技术栈',
|
||||
},
|
||||
{
|
||||
icon: '👥',
|
||||
title: '社区活跃',
|
||||
desc: 'GitHub 获得众多 star,活跃的开发者社区',
|
||||
},
|
||||
{
|
||||
icon: '🌐',
|
||||
title: '网络稳定',
|
||||
desc: '解决官方 CLI 网络不稳定问题,支持国内环境',
|
||||
},
|
||||
{
|
||||
icon: '⚡️',
|
||||
title: '开发效率',
|
||||
desc: '提升开发效率 100%,快速搭建现代化项目',
|
||||
},
|
||||
])
|
||||
|
||||
// 解决的问题
|
||||
const problems = ref([
|
||||
{
|
||||
problem: '网络问题',
|
||||
desc: 'degit 命令只支持 GitHub,国内网络不稳定',
|
||||
},
|
||||
{
|
||||
problem: '维护问题',
|
||||
desc: '官方模板维护不够积极,版本往往落后',
|
||||
},
|
||||
{
|
||||
problem: '工程化问题',
|
||||
desc: '项目配置过于基础,缺少现代工程化支持',
|
||||
},
|
||||
{
|
||||
problem: '集成问题',
|
||||
desc: '需要手动集成组件库,配置过程繁琐',
|
||||
},
|
||||
])
|
||||
|
||||
// WotUI 快速创建
|
||||
const wotQuickStart = ref({
|
||||
title: '快速创建 WotUI 项目',
|
||||
command: 'pnpm create uni@latest -t wot-starter <你的项目名称>',
|
||||
desc: '一键创建集成了 WotUI 的完整项目',
|
||||
features: [
|
||||
'✅ TypeScript 项目',
|
||||
'✅ 集成 Pinia 状态管理',
|
||||
'✅ 自动配置 WotUI 组件库',
|
||||
'✅ 添加 ESLint 支持',
|
||||
],
|
||||
})
|
||||
|
||||
// 其他使用方式
|
||||
const quickMethods = ref([
|
||||
{
|
||||
title: 'GUI 模式',
|
||||
command: 'pnpm create uni --gui',
|
||||
desc: '使用图形界面创建项目',
|
||||
},
|
||||
{
|
||||
title: '环境信息',
|
||||
command: 'npx @create-uni/info@latest',
|
||||
desc: '获取当前项目环境信息',
|
||||
},
|
||||
])
|
||||
|
||||
// 复制命令到剪贴板
|
||||
function copyCommand(command: string) {
|
||||
uni.setClipboardData({
|
||||
data: command,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({
|
||||
msg: `${command}已成功复制到剪贴板`,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
copyCommand(url)
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🌱
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
CreateUni 脚手架
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
由 uni-helper 团队开发的轻量级脚手架工具
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
提升开发效率 100%,告别繁琐配置,一键集成 WotUI 组件库
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 为什么选择 create-uni -->
|
||||
<demo-block title="为什么选择 create-uni?" transparent>
|
||||
<view class="mb-3 rounded-3 bg-white p-3 dark:bg-[var(--wot-dark-background2)]">
|
||||
<text class="text-3.5 text-gray-700 leading-relaxed dark:text-[var(--wot-dark-color)]">
|
||||
在使用 uni-app 官方 CLI 工具时,我们经常会遇到以下问题:
|
||||
</text>
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<view
|
||||
v-for="item in problems"
|
||||
:key="item.problem"
|
||||
class="mb-2 rounded-3 bg-white p-3 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-1 text-3.5 text-red-600 font-bold dark:text-red-400">
|
||||
❌ {{ item.problem }}
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]">
|
||||
{{ item.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="rounded-3 bg-white p-3 dark:bg-[var(--wot-dark-background2)]">
|
||||
<text class="text-3.5 text-green-600 font-bold dark:text-green-400">
|
||||
✅ 而 create-uni 的出现,完美解决了这些问题!
|
||||
</text>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 核心优势 -->
|
||||
<demo-block title="核心优势" transparent>
|
||||
<view class="grid grid-cols-2 gap-3">
|
||||
<view
|
||||
v-for="advantage in advantages"
|
||||
:key="advantage.title"
|
||||
class="rounded-2 bg-white p-4 text-center dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-2 text-6">
|
||||
{{ advantage.icon }}
|
||||
</view>
|
||||
<view class="mb-1 text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ advantage.title }}
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]">
|
||||
{{ advantage.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 快速创建 WotUI 项目 -->
|
||||
<demo-block title="快速创建 WotUI 项目" transparent>
|
||||
<view class="rounded-3 bg-white p-5 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-7">
|
||||
🎨
|
||||
</view>
|
||||
<view class="text-4.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ wotQuickStart.title }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
{{ wotQuickStart.desc }}
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCommand(wotQuickStart.command)">
|
||||
<text class="flex-1 break-all text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ wotQuickStart.command }}
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view>
|
||||
<view class="mb-2 text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
这个命令会:
|
||||
</view>
|
||||
<view
|
||||
v-for="feature in wotQuickStart.features"
|
||||
:key="feature"
|
||||
class="mb-1 text-3 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]"
|
||||
>
|
||||
{{ feature }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 其他使用方式 -->
|
||||
<demo-block title="其他使用方式" transparent>
|
||||
<view
|
||||
v-for="method in quickMethods"
|
||||
:key="method.title"
|
||||
class="mb-3 rounded-2 bg-white p-4 last:mb-0 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-2 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ method.title }}
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
{{ method.desc }}
|
||||
</view>
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-2 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCommand(method.command)">
|
||||
<text class="flex-1 break-all text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ method.command }}
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📦 NPM 包" value="create uni" is-link @click="handleNavigate('https://www.npmjs.com/package/create-uni')" />
|
||||
<wd-cell title="🐙 GitHub 仓库" value="create uni" is-link @click="handleNavigate('https://github.com/uni-helper/create-uni')" />
|
||||
<wd-cell title="🎨 Wot UI" value="UI 组件库" is-link @click="handleNavigate('https://wot-ui.cn/')" />
|
||||
<wd-cell title="🛠️ Uni Helper" value="先进工具集合" is-link @click="handleNavigate('https://github.com/uni-helper')" />
|
||||
<wd-cell title="💝 赞助CreateUni" value="支持开发者" is-link @click="handleNavigate('https://github.com/uni-helper/create-uni')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,72 @@
|
||||
<!--
|
||||
* @Author: weisheng
|
||||
* @Date: 2025-09-15 18:51:03
|
||||
* @LastEditTime: 2025-09-16 13:12:22
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: /wot-starter/src/subPages/echarts/components/BarChart.vue
|
||||
* 记得注释
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
import { BarChart } from 'echarts/charts'
|
||||
import { DatasetComponent, GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
DatasetComponent,
|
||||
BarChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ['销售额', '利润'],
|
||||
top: 30,
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销售额',
|
||||
type: 'bar',
|
||||
data: [120, 200, 150, 80, 70, 110],
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '利润',
|
||||
type: 'bar',
|
||||
data: [20, 40, 30, 15, 12, 22],
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import { DatasetComponent, GraphicComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
DatasetComponent,
|
||||
PieChart,
|
||||
CanvasRenderer,
|
||||
GraphicComponent,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)',
|
||||
textStyle: {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
orient: 'horizontal',
|
||||
bottom: 10,
|
||||
left: 'center',
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '用户占比',
|
||||
type: 'pie',
|
||||
radius: ['45%', '70%'],
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: '#ffffff',
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 335,
|
||||
name: 'iOS',
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 310,
|
||||
name: 'Android',
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 234,
|
||||
name: 'H5',
|
||||
itemStyle: {
|
||||
color: '#fac858',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 135,
|
||||
name: '小程序',
|
||||
itemStyle: {
|
||||
color: '#ee6666',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 86,
|
||||
name: '其他',
|
||||
itemStyle: {
|
||||
color: '#73c0de',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,116 @@
|
||||
<script setup lang="ts">
|
||||
import { FunnelChart } from 'echarts/charts'
|
||||
import { LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
FunnelChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)',
|
||||
textStyle: {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
orient: 'horizontal',
|
||||
bottom: 10,
|
||||
left: 'center',
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '销售漏斗',
|
||||
type: 'funnel',
|
||||
left: '10%',
|
||||
top: 60,
|
||||
width: '80%',
|
||||
height: '60%',
|
||||
min: 0,
|
||||
max: 100,
|
||||
minSize: '0%',
|
||||
maxSize: '100%',
|
||||
sort: 'descending',
|
||||
gap: 2,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
fontSize: 12,
|
||||
color: '#fff',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
labelLine: {
|
||||
length: 10,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
type: 'solid',
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
borderColor: '#fff',
|
||||
borderWidth: 1,
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 100,
|
||||
name: '访问量',
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 80,
|
||||
name: '浏览商品',
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 60,
|
||||
name: '加入购物车',
|
||||
itemStyle: {
|
||||
color: '#fac858',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 40,
|
||||
name: '提交订单',
|
||||
itemStyle: {
|
||||
color: '#ee6666',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 20,
|
||||
name: '支付成功',
|
||||
itemStyle: {
|
||||
color: '#73c0de',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,105 @@
|
||||
<script setup lang="ts">
|
||||
import { GaugeChart } from 'echarts/charts'
|
||||
import { TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
TooltipComponent,
|
||||
GaugeChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
formatter: '{a} <br/>{b}: {c}%',
|
||||
textStyle: {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '性能指标',
|
||||
type: 'gauge',
|
||||
center: ['50%', '60%'],
|
||||
radius: '75%',
|
||||
min: 0,
|
||||
max: 100,
|
||||
splitNumber: 10,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 10,
|
||||
color: [
|
||||
[0.3, '#ee6666'],
|
||||
[0.7, '#fac858'],
|
||||
[1, '#91cc75'],
|
||||
],
|
||||
},
|
||||
},
|
||||
pointer: {
|
||||
itemStyle: {
|
||||
color: 'auto',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
distance: -30,
|
||||
length: 8,
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
distance: -30,
|
||||
length: 30,
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
width: 4,
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'auto',
|
||||
distance: 40,
|
||||
fontSize: 12,
|
||||
},
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
formatter: '{value}%',
|
||||
color: 'auto',
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
offsetCenter: [0, '70%'],
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 75,
|
||||
name: 'CPU使用率',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 模拟数据变化
|
||||
let timer: NodeJS.Timeout | null = null
|
||||
|
||||
onMounted(() => {
|
||||
timer = setInterval(() => {
|
||||
const newValue = Math.round(Math.random() * 100)
|
||||
option.value.series[0].data[0].value = newValue
|
||||
}, 3000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,103 @@
|
||||
<script setup lang="ts">
|
||||
import { LineChart } from 'echarts/charts'
|
||||
import { DatasetComponent, GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
DatasetComponent,
|
||||
LineChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
legend: {
|
||||
data: ['访问量', '用户数'],
|
||||
top: 30,
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问量',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: [120, 132, 101, 134, 90, 230, 210],
|
||||
smooth: true,
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(84, 112, 198, 0.3)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(84, 112, 198, 0.1)',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '用户数',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: [220, 182, 191, 234, 290, 330, 310],
|
||||
smooth: true,
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(145, 204, 117, 0.3)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(145, 204, 117, 0.1)',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,142 @@
|
||||
<script setup lang="ts">
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import { TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
TooltipComponent,
|
||||
PieChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const progress = ref(68)
|
||||
|
||||
const option = computed(() => ({
|
||||
tooltip: {
|
||||
// formatter: () => `完成度: ${progress.value}%`,
|
||||
textStyle: {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
graphic: [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
style: {
|
||||
text: `完成度:${progress.value}%`,
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
fill: '#5470c6',
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['60%', '80%'],
|
||||
center: ['50%', '50%'],
|
||||
startAngle: 90,
|
||||
clockwise: true,
|
||||
silent: true,
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: progress.value,
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#5470c6',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#91cc75',
|
||||
},
|
||||
],
|
||||
},
|
||||
borderRadius: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
value: 100 - progress.value,
|
||||
itemStyle: {
|
||||
color: '#f0f0f0',
|
||||
borderRadius: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// 内圆背景
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['0%', '58%'],
|
||||
center: ['50%', '50%'],
|
||||
silent: true,
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 100,
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'radial',
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
r: 0.5,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(84, 112, 198, 0.1)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(84, 112, 198, 0.05)',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
// 模拟进度变化
|
||||
let timer: NodeJS.Timeout | null = null
|
||||
|
||||
onMounted(() => {
|
||||
timer = setInterval(() => {
|
||||
progress.value = Math.round(Math.random() * 100)
|
||||
}, 4000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,134 @@
|
||||
<script setup lang="ts">
|
||||
import { LineChart } from 'echarts/charts'
|
||||
import { GridComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
GridComponent,
|
||||
TooltipComponent,
|
||||
LineChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(50,50,50,0.8)',
|
||||
borderColor: 'transparent',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
formatter: (params: any) => {
|
||||
const param = params[0]
|
||||
return `${param.name}<br/>${param.seriesName}: ${param.value}`
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
left: '8%',
|
||||
right: '8%',
|
||||
top: '25%',
|
||||
bottom: '15%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'],
|
||||
axisLabel: {
|
||||
fontSize: 10,
|
||||
color: '#666',
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#e0e0e0',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
fontSize: 10,
|
||||
color: '#666',
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f0f0f0',
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问量',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: {
|
||||
width: 3,
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 1,
|
||||
y2: 0,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#5470c6',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#91cc75',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff',
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(84, 112, 198, 0.3)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(84, 112, 198, 0.05)',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
data: [120, 80, 150, 200, 180, 250, 160],
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import { DatasetComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
DatasetComponent,
|
||||
PieChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
legend: {
|
||||
top: 10,
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
textStyle: {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['30%', '52%'],
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: '#ffffff',
|
||||
borderRadius: 10,
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
dataset: {
|
||||
dimensions: ['来源', '数量'],
|
||||
source: [
|
||||
['Search Engine', 1048],
|
||||
['Direct', 735],
|
||||
['Email', 580],
|
||||
['Union Ads', 484],
|
||||
['Video Ads', 300],
|
||||
],
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import { RadarChart } from 'echarts/charts'
|
||||
import { LegendComponent, RadarComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
RadarComponent,
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
RadarChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
data: ['张三', '李四'],
|
||||
top: 30,
|
||||
},
|
||||
radar: {
|
||||
indicator: [
|
||||
{ name: '技术能力', max: 100 },
|
||||
{ name: '沟通能力', max: 100 },
|
||||
{ name: '学习能力', max: 100 },
|
||||
{ name: '团队协作', max: 100 },
|
||||
{ name: '创新能力', max: 100 },
|
||||
{ name: '执行力', max: 100 },
|
||||
],
|
||||
shape: 'polygon',
|
||||
splitNumber: 5,
|
||||
axisName: {
|
||||
color: '#666',
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(211, 253, 250, 0.8)',
|
||||
},
|
||||
},
|
||||
splitArea: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(211, 253, 250, 0.8)',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '能力评估',
|
||||
type: 'radar',
|
||||
data: [
|
||||
{
|
||||
value: [85, 75, 90, 80, 70, 85],
|
||||
name: '张三',
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
},
|
||||
areaStyle: {
|
||||
color: 'rgba(84, 112, 198, 0.3)',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [70, 90, 80, 85, 85, 75],
|
||||
name: '李四',
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
},
|
||||
areaStyle: {
|
||||
color: 'rgba(145, 204, 117, 0.3)',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { ScatterChart } from 'echarts/charts'
|
||||
import { DatasetComponent, GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
DatasetComponent,
|
||||
ScatterChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: (params: any) => {
|
||||
return `${params.seriesName}<br/>身高: ${params.value[0]}cm<br/>体重: ${params.value[1]}kg`
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ['男性', '女性'],
|
||||
top: 30,
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
name: '身高(cm)',
|
||||
nameLocation: 'middle',
|
||||
nameGap: 30,
|
||||
min: 150,
|
||||
max: 190,
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '体重(kg)',
|
||||
nameLocation: 'middle',
|
||||
nameGap: 30,
|
||||
min: 40,
|
||||
max: 90,
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '男性',
|
||||
type: 'scatter',
|
||||
data: [
|
||||
[175, 70],
|
||||
[180, 75],
|
||||
[170, 65],
|
||||
[185, 80],
|
||||
[172, 68],
|
||||
[178, 72],
|
||||
[182, 78],
|
||||
[168, 62],
|
||||
[176, 71],
|
||||
[174, 69],
|
||||
],
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
opacity: 0.8,
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: '#5470c6',
|
||||
borderWidth: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '女性',
|
||||
type: 'scatter',
|
||||
data: [
|
||||
[160, 50],
|
||||
[165, 55],
|
||||
[158, 48],
|
||||
[170, 60],
|
||||
[162, 52],
|
||||
[168, 58],
|
||||
[155, 45],
|
||||
[172, 62],
|
||||
[164, 54],
|
||||
[166, 56],
|
||||
],
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
opacity: 0.8,
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderColor: '#91cc75',
|
||||
borderWidth: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,127 @@
|
||||
<script setup lang="ts">
|
||||
import { BarChart } from 'echarts/charts'
|
||||
import { DatasetComponent, GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
|
||||
import * as echarts from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
|
||||
echarts.use([
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
DatasetComponent,
|
||||
BarChart,
|
||||
CanvasRenderer,
|
||||
])
|
||||
|
||||
const option = ref({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
textStyle: {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 临时解决微信小程序 tooltip 文字阴影问题
|
||||
textShadowBlur: 1,
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ['产品A', '产品B', '产品C'],
|
||||
top: 35,
|
||||
left: 'center',
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
left: '8%',
|
||||
right: '8%',
|
||||
top: '25%',
|
||||
bottom: '15%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['Q1', 'Q2', 'Q3', 'Q4'],
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#666',
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#e0e0e0',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
color: '#666',
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#f0f0f0',
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '产品A',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#5470c6',
|
||||
borderRadius: [0, 0, 0, 0],
|
||||
},
|
||||
data: [120, 132, 101, 134],
|
||||
},
|
||||
{
|
||||
name: '产品B',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#91cc75',
|
||||
borderRadius: [0, 0, 0, 0],
|
||||
},
|
||||
data: [220, 182, 191, 234],
|
||||
},
|
||||
{
|
||||
name: '产品C',
|
||||
type: 'bar',
|
||||
stack: 'total',
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#fac858',
|
||||
borderRadius: [4, 4, 0, 0],
|
||||
},
|
||||
data: [150, 212, 201, 154],
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<uni-echarts custom-class="h-300px" :option="option" />
|
||||
</template>
|
||||
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import BarChart from './components/BarChart.vue'
|
||||
import DonutChart from './components/DonutChart.vue'
|
||||
import FunnelChart from './components/FunnelChart.vue'
|
||||
import GaugeChart from './components/GaugeChart.vue'
|
||||
import LineChart from './components/LineChart.vue'
|
||||
import LiquidFillChart from './components/LiquidFillChart.vue'
|
||||
import MiniLineChart from './components/MiniLineChart.vue'
|
||||
import PieChart from './components/PieChart.vue'
|
||||
import RadarChart from './components/RadarChart.vue'
|
||||
import ScatterChart from './components/ScatterChart.vue'
|
||||
import StackedBarChart from './components/StackedBarChart.vue'
|
||||
|
||||
definePage({
|
||||
name: 'echarts',
|
||||
style: {
|
||||
navigationBarTitleText: 'Echarts 演示',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function navigateToAsync() {
|
||||
router.push({
|
||||
name: 'echartsAsync',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-gray-50 p-5">
|
||||
<!-- 异步 Echarts 入口 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-3 shadow-sm">
|
||||
<view
|
||||
class="rounded-2 bg-blue-500 px-6 py-3 text-white font-medium transition-colors hover:bg-blue-600"
|
||||
@click="navigateToAsync"
|
||||
>
|
||||
查看异步 Echarts 示例
|
||||
</view>
|
||||
</view>
|
||||
<!-- 饼图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
饼图示例
|
||||
</view>
|
||||
<PieChart />
|
||||
</view>
|
||||
|
||||
<!-- 柱状图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
柱状图示例
|
||||
</view>
|
||||
<BarChart />
|
||||
</view>
|
||||
|
||||
<!-- 折线图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
折线图示例
|
||||
</view>
|
||||
<LineChart />
|
||||
</view>
|
||||
|
||||
<!-- 雷达图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
雷达图示例
|
||||
</view>
|
||||
<RadarChart />
|
||||
</view>
|
||||
|
||||
<!-- 散点图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
散点图示例
|
||||
</view>
|
||||
<ScatterChart />
|
||||
</view>
|
||||
|
||||
<!-- 环形图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
环形图示例
|
||||
</view>
|
||||
<DonutChart />
|
||||
</view>
|
||||
|
||||
<!-- 漏斗图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
漏斗图示例
|
||||
</view>
|
||||
<FunnelChart />
|
||||
</view>
|
||||
|
||||
<!-- 仪表盘图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
仪表盘示例
|
||||
</view>
|
||||
<GaugeChart />
|
||||
</view>
|
||||
|
||||
<!-- 迷你折线图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
迷你折线图示例
|
||||
</view>
|
||||
<MiniLineChart />
|
||||
</view>
|
||||
|
||||
<!-- 堆叠柱状图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
堆叠柱状图示例
|
||||
</view>
|
||||
<StackedBarChart />
|
||||
</view>
|
||||
|
||||
<!-- 水球图 -->
|
||||
<view class="mb-5 rounded-3 bg-white p-5 shadow-sm">
|
||||
<view class="mb-5 text-center text-base text-gray-800 font-medium">
|
||||
水球图示例
|
||||
</view>
|
||||
<LiquidFillChart />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,581 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'feedback',
|
||||
style: {
|
||||
navigationBarTitleText: '全局反馈',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
const { show: showToast, success, error, warning, info } = useGlobalToast()
|
||||
const { loading, close: closeLoading } = useGlobalLoading()
|
||||
const { confirm, alert, prompt } = useGlobalMessage()
|
||||
|
||||
// 表单数据
|
||||
const customMessage = ref('这是一个自定义消息')
|
||||
const loadingText = ref('正在处理中...')
|
||||
|
||||
// Toast 演示方法
|
||||
function demoToastSuccess() {
|
||||
success({ msg: '操作成功!' })
|
||||
}
|
||||
|
||||
function demoToastError() {
|
||||
error({ msg: '操作失败!' })
|
||||
}
|
||||
|
||||
function demoToastWarning() {
|
||||
warning({ msg: '警告提示!' })
|
||||
}
|
||||
|
||||
function demoToastInfo() {
|
||||
info({ msg: '信息提示!' })
|
||||
}
|
||||
|
||||
function demoCustomToast() {
|
||||
if (!customMessage.value.trim()) {
|
||||
warning({ msg: '请输入自定义消息' })
|
||||
return
|
||||
}
|
||||
showToast({
|
||||
msg: customMessage.value,
|
||||
duration: 3000,
|
||||
position: 'middle',
|
||||
})
|
||||
}
|
||||
|
||||
function demoToastPosition(position: 'top' | 'middle' | 'bottom') {
|
||||
showToast({
|
||||
msg: `显示在${position === 'top' ? '顶部' : position === 'middle' ? '中间' : '底部'}的提示`,
|
||||
position,
|
||||
duration: 2000,
|
||||
})
|
||||
}
|
||||
|
||||
// Loading 演示方法
|
||||
function demoBasicLoading() {
|
||||
loading('加载中...')
|
||||
setTimeout(() => {
|
||||
closeLoading()
|
||||
success({ msg: '加载完成!' })
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
function demoCustomLoading() {
|
||||
if (!loadingText.value.trim()) {
|
||||
warning({ msg: '请输入加载文本' })
|
||||
return
|
||||
}
|
||||
loading({
|
||||
msg: loadingText.value,
|
||||
cover: true,
|
||||
})
|
||||
setTimeout(() => {
|
||||
closeLoading()
|
||||
success({ msg: '自定义加载完成!' })
|
||||
}, 2500)
|
||||
}
|
||||
|
||||
function demoLoadingNoCover() {
|
||||
loading({
|
||||
msg: '无遮罩加载',
|
||||
cover: false,
|
||||
})
|
||||
setTimeout(() => {
|
||||
closeLoading()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// Message 演示方法
|
||||
function demoConfirm() {
|
||||
confirm({
|
||||
title: '确认操作',
|
||||
msg: '您确定要执行此操作吗?',
|
||||
success: (res) => {
|
||||
if (res.action === 'confirm') {
|
||||
success({ msg: '用户确认了操作' })
|
||||
}
|
||||
else {
|
||||
info({ msg: '用户取消了操作' })
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function demoAlert() {
|
||||
alert({
|
||||
title: '重要提醒',
|
||||
msg: '这是一个重要的提醒信息,请仔细阅读!',
|
||||
success: () => {
|
||||
success({ msg: '用户已阅读提醒' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function demoPrompt() {
|
||||
prompt({
|
||||
title: '输入信息',
|
||||
msg: '请输入您的姓名:',
|
||||
success: (res) => {
|
||||
if (res.action === 'confirm') {
|
||||
if (res.value && String(res.value).trim()) {
|
||||
success({ msg: `您好,${res.value}!` })
|
||||
}
|
||||
else {
|
||||
warning({ msg: '输入不能为空' })
|
||||
}
|
||||
}
|
||||
else {
|
||||
info({ msg: '用户取消了输入' })
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function demoCustomConfirm() {
|
||||
confirm({
|
||||
title: '自定义确认',
|
||||
msg: '这是一个自定义的确认弹窗,可以配置按钮文字和样式',
|
||||
confirmButtonText: '好的',
|
||||
cancelButtonText: '算了',
|
||||
success: (res) => {
|
||||
if (res.action === 'confirm') {
|
||||
success({ msg: '点击了"好的"' })
|
||||
}
|
||||
else {
|
||||
info({ msg: '点击了"算了"' })
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 组合演示
|
||||
function demoComplex() {
|
||||
loading('准备演示...')
|
||||
|
||||
setTimeout(() => {
|
||||
closeLoading()
|
||||
confirm({
|
||||
title: '组合演示',
|
||||
msg: '这是一个组合演示,将依次展示不同的反馈效果。是否继续?',
|
||||
success: (res) => {
|
||||
if (res.action === 'confirm') {
|
||||
success({ msg: '开始演示' })
|
||||
|
||||
setTimeout(() => {
|
||||
loading('演示进行中...')
|
||||
|
||||
setTimeout(() => {
|
||||
closeLoading()
|
||||
info({ msg: '演示完成!' })
|
||||
}, 2000)
|
||||
}, 1000)
|
||||
}
|
||||
else {
|
||||
info({ msg: '已取消演示' })
|
||||
}
|
||||
},
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 代码示例常量
|
||||
const codeExamples = {
|
||||
basicToast: `const { success, error, warning, info } = useGlobalToast()
|
||||
|
||||
// 使用方法
|
||||
success({ msg: '操作成功!' })
|
||||
error({ msg: '操作失败!' })
|
||||
warning({ msg: '警告提示!' })
|
||||
info({ msg: '信息提示!' })`,
|
||||
|
||||
customToast: `const { show } = useGlobalToast()
|
||||
|
||||
show({
|
||||
msg: '自定义消息',
|
||||
duration: 3000,
|
||||
position: 'middle' // 'top' | 'middle' | 'bottom'
|
||||
})`,
|
||||
|
||||
basicLoading: `const { loading, close } = useGlobalLoading()
|
||||
|
||||
// 基础用法
|
||||
loading('加载中...')
|
||||
|
||||
// 手动关闭
|
||||
close()`,
|
||||
|
||||
customLoading: `loading({
|
||||
msg: '正在处理中...',
|
||||
cover: true // 是否显示遮罩
|
||||
})`,
|
||||
|
||||
basicMessage: `const { confirm, alert, prompt } = useGlobalMessage()
|
||||
|
||||
// 确认弹窗
|
||||
confirm({
|
||||
title: '确认操作',
|
||||
msg: '您确定要执行此操作吗?',
|
||||
success: (res) => {
|
||||
if (res.action === 'confirm') {
|
||||
// 用户确认
|
||||
}
|
||||
}
|
||||
})`,
|
||||
|
||||
customMessage: `confirm({
|
||||
title: '自定义确认',
|
||||
msg: '自定义的确认弹窗',
|
||||
confirmButtonText: '好的',
|
||||
cancelButtonText: '算了',
|
||||
success: (res) => {
|
||||
// res.action: 'confirm' | 'cancel'
|
||||
}
|
||||
})`,
|
||||
}
|
||||
|
||||
// 复制代码到剪贴板
|
||||
function copyCode(code: string) {
|
||||
uni.setClipboardData({
|
||||
data: code,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: '代码已复制到剪贴板' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: `${url} 已复制到剪贴板` })
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
💬
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
全局反馈组件
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
GlobalToast / GlobalLoading / GlobalMessage
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
统一的用户反馈交互体验,支持在路由导航守卫和网络请求拦截器中使用,扩展 WotUI 交互组件能力。
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- GlobalToast 演示 -->
|
||||
<demo-block title="GlobalToast 轻提示" transparent>
|
||||
<view class="space-y-4">
|
||||
<!-- 基础用法 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
基础用法
|
||||
</view>
|
||||
<view class="grid grid-cols-2 mb-3 gap-2">
|
||||
<wd-button type="success" size="small" @click="demoToastSuccess">
|
||||
成功提示
|
||||
</wd-button>
|
||||
<wd-button type="error" size="small" @click="demoToastError">
|
||||
错误提示
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="demoToastWarning">
|
||||
警告提示
|
||||
</wd-button>
|
||||
<wd-button type="info" size="small" @click="demoToastInfo">
|
||||
信息提示
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(codeExamples.basicToast)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
代码示例:
|
||||
</view>
|
||||
<view class="whitespace-pre-line text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
const { success, error, warning, info } = useGlobalToast()
|
||||
|
||||
success({ msg: '操作成功!' })
|
||||
error({ msg: '操作失败!' })
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义用法 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义配置
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<wd-input v-model="customMessage" placeholder="请输入自定义消息" />
|
||||
</view>
|
||||
<view class="grid grid-cols-2 mb-3 gap-2">
|
||||
<wd-button type="primary" size="small" @click="demoCustomToast">
|
||||
自定义消息
|
||||
</wd-button>
|
||||
<wd-button type="success" size="small" @click="demoToastPosition('top')">
|
||||
顶部显示
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="demoToastPosition('middle')">
|
||||
中间显示
|
||||
</wd-button>
|
||||
<wd-button type="info" size="small" @click="demoToastPosition('bottom')">
|
||||
底部显示
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(codeExamples.customToast)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义配置:
|
||||
</view>
|
||||
<view class="whitespace-pre-line text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
show({
|
||||
msg: '自定义消息',
|
||||
duration: 3000,
|
||||
position: 'middle'
|
||||
})
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- GlobalLoading 演示 -->
|
||||
<demo-block title="GlobalLoading 加载提示" transparent>
|
||||
<view class="space-y-4">
|
||||
<!-- 基础用法 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
基础用法
|
||||
</view>
|
||||
<view class="grid grid-cols-2 mb-3 gap-2">
|
||||
<wd-button type="primary" size="small" @click="demoBasicLoading">
|
||||
显示加载(3秒)
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="closeLoading">
|
||||
手动关闭
|
||||
</wd-button>
|
||||
<wd-button type="success" size="small" @click="demoLoadingNoCover">
|
||||
无遮罩加载
|
||||
</wd-button>
|
||||
<wd-button type="info" size="small" @click="demoComplex">
|
||||
组合演示
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(codeExamples.basicLoading)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
代码示例:
|
||||
</view>
|
||||
<view class="whitespace-pre-line text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
const { loading, close } = useGlobalLoading()
|
||||
|
||||
loading('加载中...')
|
||||
close()
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义用法 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义配置
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<wd-input v-model="loadingText" placeholder="请输入加载文本" />
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<wd-button type="primary" block @click="demoCustomLoading">
|
||||
自定义加载文本
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(codeExamples.customLoading)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义配置:
|
||||
</view>
|
||||
<view class="whitespace-pre-line text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
loading({
|
||||
msg: '正在处理中...',
|
||||
cover: true // 是否显示遮罩
|
||||
})
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- GlobalMessage 演示 -->
|
||||
<demo-block title="GlobalMessage 弹窗提示" transparent>
|
||||
<view class="space-y-4">
|
||||
<!-- 基础用法 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
基础用法
|
||||
</view>
|
||||
<view class="grid grid-cols-3 mb-3 gap-2">
|
||||
<wd-button type="primary" size="small" @click="demoConfirm">
|
||||
确认弹窗
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="demoAlert">
|
||||
警告弹窗
|
||||
</wd-button>
|
||||
<wd-button type="success" size="small" @click="demoPrompt">
|
||||
输入弹窗
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(codeExamples.basicMessage)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
代码示例:
|
||||
</view>
|
||||
<view class="whitespace-pre-line text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
confirm({
|
||||
title: '确认操作',
|
||||
msg: '您确定要执行此操作吗?',
|
||||
success: (res) => { /* 处理结果 */ }
|
||||
})
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义用法 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义配置
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<wd-button type="primary" block @click="demoCustomConfirm">
|
||||
自定义按钮文字
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(codeExamples.customMessage)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义按钮:
|
||||
</view>
|
||||
<view class="whitespace-pre-line text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
confirm({
|
||||
confirmButtonText: '好的',
|
||||
cancelButtonText: '算了'
|
||||
})
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 组件特性 -->
|
||||
<demo-block title="组件特性" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
🎯
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
设计理念
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>
|
||||
• <text class="text-blue-600 font-bold dark:text-blue-400">
|
||||
全局单例
|
||||
</text>:整个应用只有一个实例,避免重复创建
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-green-600 font-bold dark:text-green-400">
|
||||
状态管理
|
||||
</text>:基于 Pinia 管理组件状态,响应式更新
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-purple-600 font-bold dark:text-purple-400">
|
||||
类型安全
|
||||
</text>:完整的 TypeScript 类型定义
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-orange-600 font-bold dark:text-orange-400">
|
||||
易于使用
|
||||
</text>:简洁的 API 设计,开箱即用
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
⚡
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
使用优势
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• 统一的用户反馈体验</view>
|
||||
<view>• 避免组件重复创建和销毁</view>
|
||||
<view>• 支持深色模式自动适配</view>
|
||||
<view>• 可在任意组件中调用</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
📝
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
最佳实践
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• Toast:用于简短的状态反馈,不打断用户操作</view>
|
||||
<view>• Loading:用于异步操作的等待提示</view>
|
||||
<view>• Message:用于重要信息确认和用户输入</view>
|
||||
<view>• 合理控制显示时长,避免信息过载</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📚 WotUI Toast" value="轻提示组件" is-link @click="handleNavigate('https://wot-ui.cn/component/toast.html')" />
|
||||
<wd-cell title="🔄 WotUI Loading" value="加载组件" is-link @click="handleNavigate('https://wot-ui.cn/component/loading.html')" />
|
||||
<wd-cell title="💬 WotUI MessageBox" value="弹窗组件" is-link @click="handleNavigate('https://wot-ui.cn/component/message-box.html')" />
|
||||
<wd-cell title="🍍 Pinia 状态管理" value="Vue 状态库" is-link @click="handleNavigate('https://pinia.vuejs.org/zh/')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,483 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'icon',
|
||||
style: {
|
||||
navigationBarTitleText: '图标演示',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
|
||||
// WotUI 内置图标列表(精选9个)
|
||||
const wotIcons = ref([
|
||||
{ name: 'add', desc: '添加' },
|
||||
{ name: 'close', desc: '关闭' },
|
||||
{ name: 'check', desc: '勾选' },
|
||||
{ name: 'arrow-right', desc: '右箭头' },
|
||||
{ name: 'bags', desc: '购物袋' },
|
||||
{ name: 'search', desc: '搜索' },
|
||||
{ name: 'star', desc: '星标' },
|
||||
{ name: 'heart', desc: '喜欢' },
|
||||
{ name: 'setting', desc: '设置' },
|
||||
])
|
||||
|
||||
// Carbon 图标是编译时的,不能动态渲染,所以直接在模板中静态写入
|
||||
|
||||
// 图标大小选项
|
||||
const iconSizes = ref([
|
||||
{ name: '小', value: '16px' },
|
||||
{ name: '中', value: '20px' },
|
||||
{ name: '大', value: '24px' },
|
||||
{ name: '超大', value: '32px' },
|
||||
])
|
||||
const currentIconSize = ref('20px')
|
||||
|
||||
// 复制图标代码
|
||||
function copyIconCode(iconName: string, isCarbon = false) {
|
||||
const code = isCarbon
|
||||
? `<div class="i-carbon:${iconName} text-xl"></div>`
|
||||
: `<wd-icon name="${iconName}" size="20px" />`
|
||||
|
||||
uni.setClipboardData({
|
||||
data: code,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: '代码已复制到剪贴板' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: `${url} 已复制到剪贴板` })
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🎯
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
图标使用演示
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
WotUI 图标 & Iconify 图标集
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
丰富的图标资源,满足各种使用场景
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图标大小选择 -->
|
||||
<demo-block title="图标大小" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
选择图标大小
|
||||
</view>
|
||||
<view class="mb-4 flex flex-wrap gap-2">
|
||||
<view
|
||||
v-for="size in iconSizes"
|
||||
:key="size.value"
|
||||
class="rounded-2 px-3 py-2 text-3 transition-all duration-200"
|
||||
:class="[
|
||||
currentIconSize === size.value
|
||||
? 'bg-blue-500 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color)] dark:hover:bg-[var(--wot-dark-border)]',
|
||||
]"
|
||||
@click="currentIconSize = size.value"
|
||||
>
|
||||
{{ size.name }} ({{ size.value }})
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex items-center justify-center rounded-2 bg-gray-50 p-4 space-x-4 dark:bg-[var(--wot-dark-background3)]">
|
||||
<wd-icon name="star" :size="currentIconSize" color="#f59e0b" />
|
||||
<view class="i-carbon:star text-yellow-500" :style="{ fontSize: currentIconSize }" />
|
||||
<text class="text-3 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
当前大小: {{ currentIconSize }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- WotUI 图标 -->
|
||||
<demo-block title="WotUI 内置图标(精选示例)" transparent>
|
||||
<!-- 说明文字 -->
|
||||
<view class="mb-4 border border-blue-200 rounded-2 bg-blue-50 p-3 dark:border-blue-800 dark:bg-blue-900/20">
|
||||
<view class="mb-1 text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
💡 说明
|
||||
</view>
|
||||
<view class="text-3 text-blue-600 leading-relaxed dark:text-blue-200">
|
||||
这里只展示了部分常用图标作为示例。完整的图标列表请查看
|
||||
<text class="text-blue-700 underline dark:text-blue-300" @click="handleNavigate('https://wot-ui.cn/component/icon.html')">
|
||||
WotUI 官方文档
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图标网格 -->
|
||||
<view class="grid grid-cols-3 gap-3 md:grid-cols-6 sm:grid-cols-4">
|
||||
<view
|
||||
v-for="icon in wotIcons"
|
||||
:key="icon.name"
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode(icon.name)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<wd-icon :name="icon.name" :size="currentIconSize" color="#666" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ icon.name }}
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
{{ icon.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 使用示例 -->
|
||||
<view class="mt-4 rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
使用示例
|
||||
</view>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
基础用法:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
<wd-icon name="star" size="20px" color="#f59e0b" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义样式:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
<wd-icon name="home" size="24px" color="var(--wot-color-theme)" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- Carbon 图标 -->
|
||||
<demo-block title="Carbon 图标集" transparent>
|
||||
<view class="mb-4 border border-blue-200 rounded-2 bg-blue-50 p-3 dark:border-blue-800 dark:bg-blue-900/20">
|
||||
<view class="mb-1 text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
💡 说明
|
||||
</view>
|
||||
<view class="text-3 text-blue-600 leading-relaxed dark:text-blue-200">
|
||||
Iconify 图标集资源异常丰富,这里我们以 Carbon 图标集为例,展示如何使用图标。
|
||||
<text class="text-blue-700 underline dark:text-blue-300" @click="handleNavigate('https://icones.js.org/collection/carbon')">
|
||||
Carbon 图标集
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图标网格 - 静态渲染 -->
|
||||
<view class="grid grid-cols-3 gap-3 md:grid-cols-6 sm:grid-cols-4">
|
||||
<!-- add -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('add', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:add text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
add
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
添加
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- close -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('close', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:close text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
close
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
关闭
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- checkmark -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('checkmark', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:checkmark text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
checkmark
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
确认
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- arrow-right -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('arrow-right', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:arrow-right text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
arrow-right
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
右箭头
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- home -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('home', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:home text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
home
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
首页
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- search -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('search', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:search text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
search
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
搜索
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- star -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('star', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:star text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
star
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
星级
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- favorite -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('favorite', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:favorite text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
favorite
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
收藏
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- settings -->
|
||||
<view
|
||||
class="rounded-2 bg-white p-4 text-center transition-all duration-200 active:scale-95 dark:bg-[var(--wot-dark-background2)] hover:shadow-md"
|
||||
@click="copyIconCode('settings', true)"
|
||||
>
|
||||
<view class="mb-2 flex justify-center">
|
||||
<view class="i-carbon:settings text-gray-600 dark:text-[var(--wot-dark-color)]" :style="{ fontSize: currentIconSize }" />
|
||||
</view>
|
||||
<view class="mb-1 text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
settings
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
设置
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 使用示例 -->
|
||||
<view class="mt-4 rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
使用示例
|
||||
</view>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
UnoCSS 方式:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
<div class="i-carbon:star text-xl text-yellow-500"></div>
|
||||
</view>
|
||||
</view>
|
||||
<view class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
自定义大小和颜色:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
<div class="i-carbon:home" style="font-size: 24px; color: #3b82f6;"></div>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 对比演示 -->
|
||||
<demo-block title="图标对比" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-4 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
相同功能图标对比
|
||||
</view>
|
||||
<view class="space-y-4">
|
||||
<view class="grid grid-cols-2 gap-4">
|
||||
<view class="rounded-2 bg-blue-50 p-4 text-center dark:bg-blue-900/20">
|
||||
<view class="mb-2 text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
WotUI 图标
|
||||
</view>
|
||||
<view class="mb-3 flex justify-center space-x-4">
|
||||
<wd-icon name="home" :size="20" color="#3b82f6" />
|
||||
<wd-icon name="search1" :size="20" color="#3b82f6" />
|
||||
<wd-icon name="star" :size="20" color="#3b82f6" />
|
||||
<wd-icon name="heart" :size="20" color="#3b82f6" />
|
||||
</view>
|
||||
<view class="text-2.5 text-blue-600 dark:text-blue-200">
|
||||
组件化使用,API统一
|
||||
</view>
|
||||
</view>
|
||||
<view class="rounded-2 bg-green-50 p-4 text-center dark:bg-green-900/20">
|
||||
<view class="mb-2 text-3.5 text-green-700 font-bold dark:text-green-300">
|
||||
Iconify 图标
|
||||
</view>
|
||||
<view class="mb-3 flex justify-center space-x-4">
|
||||
<view class="i-carbon:home text-20px text-green-600" />
|
||||
<view class="i-carbon:search text-20px text-green-600" />
|
||||
<view class="i-carbon:star text-20px text-green-600" />
|
||||
<view class="i-carbon:favorite text-20px text-green-600" />
|
||||
</view>
|
||||
<view class="text-2.5 text-green-600 dark:text-green-200">
|
||||
原子化CSS,更加灵活
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 使用建议 -->
|
||||
<demo-block title="使用建议" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
💡
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
WotUI 图标适用场景
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• 与WotUI组件配合使用时</view>
|
||||
<view>• 需要统一的图标API时</view>
|
||||
<view>• 快速开发,不需要过多自定义时</view>
|
||||
<view>• 移动端应用,需要保证兼容性时</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
🎨
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
Iconify 图标适用场景
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• 需要更多图标选择时</view>
|
||||
<view>• 使用UnoCSS原子化CSS时</view>
|
||||
<view>• 需要灵活自定义样式时</view>
|
||||
<view>• 追求更小的包体积时</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
🤝
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
结合使用建议
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>
|
||||
• <text class="text-blue-600 font-bold dark:text-blue-400">
|
||||
WotUI图标
|
||||
</text>:用于组件内置图标,如按钮、表单等
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-green-600 font-bold dark:text-green-400">
|
||||
Iconify图标
|
||||
</text>:用于装饰性图标,如页面图标、状态图标等
|
||||
</view>
|
||||
<view>• 两者可以在同一个项目中混用,各取所长</view>
|
||||
<view>• 建议制定团队规范,明确使用场景</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📚 WotUI 图标文档" value="组件库文档" is-link @click="handleNavigate('https://wot-ui.cn/component/icon.html')" />
|
||||
<wd-cell title="🎯 Carbon 图标集" value="IBM设计系统" is-link @click="handleNavigate('https://icones.js.org/collection/carbon')" />
|
||||
<wd-cell title="🔧 Iconify 图标集" value="巨量图标合集" is-link @click="handleNavigate('https://iconify.design/')" />
|
||||
<wd-cell title="⚡ UnoCSS 图标" value="原子化CSS图标" is-link @click="handleNavigate('https://unocss.dev/presets/icons')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,547 @@
|
||||
<script setup lang="ts">
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
definePage({
|
||||
name: 'pinia',
|
||||
style: {
|
||||
navigationBarTitleText: 'Pinia 演示',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
|
||||
// 定义一个基础的计数器store
|
||||
const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
|
||||
function decrement() {
|
||||
count.value--
|
||||
}
|
||||
|
||||
function reset() {
|
||||
count.value = 0
|
||||
}
|
||||
|
||||
return {
|
||||
count,
|
||||
doubleCount,
|
||||
increment,
|
||||
decrement,
|
||||
reset,
|
||||
}
|
||||
})
|
||||
|
||||
// 定义一个用户信息store(演示持久化)
|
||||
const useUserStore = defineStore('user', () => {
|
||||
const userInfo = ref({
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: '',
|
||||
theme: 'light',
|
||||
})
|
||||
|
||||
const isLoggedIn = computed(() => !!userInfo.value.name)
|
||||
|
||||
function setUserInfo(info: Partial<typeof userInfo.value>) {
|
||||
userInfo.value = { ...userInfo.value, ...info }
|
||||
}
|
||||
|
||||
function clearUserInfo() {
|
||||
userInfo.value = {
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: '',
|
||||
theme: 'light',
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
userInfo.value.theme = userInfo.value.theme === 'light' ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
return {
|
||||
userInfo,
|
||||
isLoggedIn,
|
||||
setUserInfo,
|
||||
clearUserInfo,
|
||||
toggleTheme,
|
||||
}
|
||||
})
|
||||
|
||||
// 定义一个临时store(不持久化)
|
||||
const useTempStore = defineStore('temp', () => {
|
||||
const tempData = ref({
|
||||
message: '',
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
|
||||
function setMessage(msg: string) {
|
||||
tempData.value.message = msg
|
||||
tempData.value.timestamp = Date.now()
|
||||
}
|
||||
|
||||
function clearMessage() {
|
||||
tempData.value.message = ''
|
||||
tempData.value.timestamp = Date.now()
|
||||
}
|
||||
|
||||
return {
|
||||
tempData,
|
||||
setMessage,
|
||||
clearMessage,
|
||||
}
|
||||
})
|
||||
|
||||
// 使用stores
|
||||
const counterStore = useCounterStore()
|
||||
const userStore = useUserStore()
|
||||
const tempStore = useTempStore()
|
||||
|
||||
// 表单数据
|
||||
const userForm = ref({
|
||||
name: '',
|
||||
email: '',
|
||||
})
|
||||
|
||||
const tempMessage = ref('')
|
||||
|
||||
// 复制代码到剪贴板
|
||||
function copyCode(code: string) {
|
||||
uni.setClipboardData({
|
||||
data: code,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: '代码已复制到剪贴板' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 保存用户信息
|
||||
function saveUserInfo() {
|
||||
if (!userForm.value.name) {
|
||||
uni.showToast({
|
||||
title: '请输入用户名',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
userStore.setUserInfo({
|
||||
name: userForm.value.name,
|
||||
email: userForm.value.email,
|
||||
avatar: '😆',
|
||||
})
|
||||
|
||||
showSuccess({ msg: '用户信息已保存(会持久化)' })
|
||||
}
|
||||
|
||||
// 设置临时消息
|
||||
function setTempMessage() {
|
||||
if (!tempMessage.value) {
|
||||
uni.showToast({
|
||||
title: '请输入消息内容',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
tempStore.setMessage(tempMessage.value)
|
||||
tempMessage.value = ''
|
||||
showSuccess({ msg: '临时消息已设置(不会持久化)' })
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: `${url} 已复制到剪贴板` })
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🍍
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
Pinia 状态管理
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
Vue 3 的直观状态管理库
|
||||
</view>
|
||||
<view class="mb-2 text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
轻量、类型安全、支持组合式API
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
本项目默认持久化所有 Store 数据,开发者可以配置排除列表
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 基础计数器演示 -->
|
||||
<demo-block title="基础使用 - 计数器" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-4 text-center">
|
||||
<view class="mb-2 text-8 text-blue-500">
|
||||
{{ counterStore.count }}
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
双倍值: {{ counterStore.doubleCount }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="grid grid-cols-3 mb-4 gap-2">
|
||||
<wd-button type="success" size="small" @click="counterStore.increment">
|
||||
+1
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="counterStore.decrement">
|
||||
-1
|
||||
</wd-button>
|
||||
<wd-button type="info" size="small" @click="counterStore.reset">
|
||||
重置
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<!-- 代码示例 -->
|
||||
<view class="space-y-3">
|
||||
<view class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
定义 Store:
|
||||
</view>
|
||||
<view
|
||||
class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]" @click="copyCode(`const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
|
||||
function increment() {
|
||||
count.value++
|
||||
}
|
||||
|
||||
return { count, doubleCount, increment }
|
||||
})`)"
|
||||
>
|
||||
const useCounterStore = defineStore('counter', () => {\n
|
||||
const count = ref(0)\n
|
||||
const doubleCount = computed(() => count.value * 2)\n
|
||||
function increment() { count.value++ }\n
|
||||
return { count, doubleCount, increment }\n
|
||||
})
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
使用 Store:
|
||||
</view>
|
||||
<view
|
||||
class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]" @click="copyCode(`const counterStore = useCounterStore()
|
||||
// 直接使用
|
||||
counterStore.increment()
|
||||
// 响应式访问
|
||||
console.log(counterStore.count)`)"
|
||||
>
|
||||
const counterStore = useCounterStore()\n
|
||||
counterStore.increment() // 调用方法\n
|
||||
console.log(counterStore.count) // 访问状态
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 用户信息演示(持久化) -->
|
||||
<demo-block title="持久化演示 - 用户信息" transparent>
|
||||
<view class="mb-3 border border-green-200 rounded-2 bg-green-50 p-3 dark:border-green-800 dark:bg-green-900/20">
|
||||
<view class="mb-1 text-3.5 text-green-700 font-bold dark:text-green-300">
|
||||
✅ 持久化存储
|
||||
</view>
|
||||
<view class="text-3 text-green-600 leading-relaxed dark:text-green-200">
|
||||
这个 Store 的数据会自动保存到本地存储,刷新页面后数据不会丢失
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="space-y-4">
|
||||
<!-- 当前用户信息 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
当前用户信息
|
||||
</view>
|
||||
|
||||
<view v-if="userStore.isLoggedIn" class="flex items-center space-x-3">
|
||||
<view class="rounded-full text-12">
|
||||
{{ userStore.userInfo.avatar }}
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ userStore.userInfo.name }}
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
{{ userStore.userInfo.email }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="text-center text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
暂无用户信息
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户信息表单 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
设置用户信息
|
||||
</view>
|
||||
|
||||
<view class="space-y-3">
|
||||
<view>
|
||||
<view class="mb-1 text-3 text-gray-700 dark:text-[var(--wot-dark-color)]">
|
||||
用户名:
|
||||
</view>
|
||||
<wd-input v-model="userForm.name" placeholder="请输入用户名" />
|
||||
</view>
|
||||
|
||||
<view>
|
||||
<view class="mb-1 text-3 text-gray-700 dark:text-[var(--wot-dark-color)]">
|
||||
邮箱:
|
||||
</view>
|
||||
<wd-input v-model="userForm.email" placeholder="请输入邮箱" />
|
||||
</view>
|
||||
|
||||
<view class="grid grid-cols-2 gap-2">
|
||||
<wd-button type="primary" @click="saveUserInfo">
|
||||
保存信息
|
||||
</wd-button>
|
||||
<wd-button type="error" @click="userStore.clearUserInfo">
|
||||
清除信息
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 临时数据演示(不持久化) -->
|
||||
<demo-block title="非持久化演示 - 临时数据" transparent>
|
||||
<view class="mb-3 border border-orange-200 rounded-2 bg-orange-50 p-3 dark:border-orange-800 dark:bg-orange-900/20">
|
||||
<view class="mb-1 text-3.5 text-orange-700 font-bold dark:text-orange-300">
|
||||
⚠️ 临时存储
|
||||
</view>
|
||||
<view class="text-3 text-orange-600 leading-relaxed dark:text-orange-200">
|
||||
这个 Store 的数据不会持久化,刷新页面后数据会丢失
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
临时消息
|
||||
</view>
|
||||
|
||||
<view v-if="tempStore.tempData.message" class="mb-4 rounded-2 bg-blue-50 p-3 dark:bg-blue-900/20">
|
||||
<view class="text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
{{ tempStore.tempData.message }}
|
||||
</view>
|
||||
<view class="text-2.5 text-blue-600 dark:text-blue-200">
|
||||
时间戳: {{ new Date(tempStore.tempData.timestamp).toLocaleString() }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="mb-4 text-center text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
暂无临时消息
|
||||
</view>
|
||||
|
||||
<view class="space-y-3">
|
||||
<wd-input v-model="tempMessage" placeholder="请输入临时消息" />
|
||||
<view class="grid grid-cols-2 gap-2">
|
||||
<wd-button type="primary" size="small" @click="setTempMessage">
|
||||
设置消息
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="tempStore.clearMessage">
|
||||
清除消息
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 持久化原理 -->
|
||||
<demo-block title="持久化实现原理" transparent>
|
||||
<view class="space-y-4">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
持久化插件
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
项目使用自定义的 Pinia 插件实现持久化,位于 <text class="text-blue-600 font-mono dark:text-blue-400">
|
||||
src/store/persist.ts
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(`function persist({ store }, excludedIds) {
|
||||
// 检查是否需要排除
|
||||
if (excludedIds.includes(store.$id)) return
|
||||
|
||||
// 从本地存储读取数据
|
||||
const storageState = uni.getStorageSync(store.$id)
|
||||
if (storageState) {
|
||||
store.$state = storageState
|
||||
}
|
||||
|
||||
// 监听状态变化并保存
|
||||
store.$subscribe(() => {
|
||||
uni.setStorageSync(store.$id, store.$state)
|
||||
})
|
||||
}`)"
|
||||
>
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
核心实现:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
function persist({ store }, excludedIds) {\n
|
||||
// 检查是否需要排除\n
|
||||
if (excludedIds.includes(store.$id)) return\n
|
||||
// 从本地存储读取数据\n
|
||||
const storageState = uni.getStorageSync(store.$id)\n
|
||||
// 监听状态变化并保存\n
|
||||
store.$subscribe(() => {\n
|
||||
uni.setStorageSync(store.$id, store.$state)\n
|
||||
})\n
|
||||
}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
排除列表
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
可以通过排除列表控制哪些 Store 不需要持久化
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="rounded bg-gray-100 p-3 dark:bg-[var(--wot-dark-background3)]" @click="copyCode(`// 在 persist.ts 中配置排除列表
|
||||
persist(context, ['global-register', 'temp'])`)"
|
||||
>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
// 当前排除的 Store ID:\n
|
||||
['global-register', 'temp']
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
使用说明
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>
|
||||
• <text class="text-green-600 font-bold dark:text-green-400">
|
||||
自动持久化
|
||||
</text>:默认情况下,所有 Store 都会自动持久化
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-orange-600 font-bold dark:text-orange-400">
|
||||
排除机制
|
||||
</text>:通过 Store ID 控制哪些不需要持久化
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-blue-600 font-bold dark:text-blue-400">
|
||||
深拷贝保护
|
||||
</text>:使用深拷贝避免引用问题
|
||||
</view>
|
||||
<view>
|
||||
• <text class="text-purple-600 font-bold dark:text-purple-400">
|
||||
自动恢复
|
||||
</text>:页面刷新时自动从本地存储恢复数据
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 最佳实践 -->
|
||||
<demo-block title="最佳实践" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
💡
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
Store 设计建议
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• 使用组合式 API 风格定义 Store</view>
|
||||
<view>• 合理拆分 Store,避免单个 Store 过于庞大</view>
|
||||
<view>• 使用 TypeScript 获得更好的类型支持</view>
|
||||
<view>• 为 Store 提供清晰的命名和注释</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
🔒
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
持久化建议
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• 敏感数据(如密码)不要持久化存储</view>
|
||||
<view>• 大量数据考虑使用数据库而非本地存储</view>
|
||||
<view>• 临时状态(如加载状态)不需要持久化</view>
|
||||
<view>• 定期清理无用的持久化数据</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-6">
|
||||
⚡
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
性能优化
|
||||
</view>
|
||||
</view>
|
||||
<view class="text-3 text-gray-600 leading-relaxed space-y-2 dark:text-[var(--wot-dark-color2)]">
|
||||
<view>• 避免在 Store 中存储大量数据</view>
|
||||
<view>• 使用 computed 缓存复杂计算结果</view>
|
||||
<view>• 合理使用 $subscribe 监听状态变化</view>
|
||||
<view>• 考虑使用 $patch 批量更新状态</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📚 Pinia 官方文档" value="状态管理库" is-link @click="handleNavigate('https://pinia.vuejs.org/zh/')" />
|
||||
<wd-cell title="🎯 Vue 3 文档" value="组合式 API" is-link @click="handleNavigate('https://cn.vuejs.org/guide/extras/composition-api-faq.html')" />
|
||||
<wd-cell title="🔧 uni-app 存储" value="本地存储 API" is-link @click="handleNavigate('https://uniapp.dcloud.net.cn/api/storage/storage.html')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,507 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormRules } from 'wot-design-uni/components/wd-form/types'
|
||||
import type { UserInfo } from '@/api/user'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
||||
import UserAPI from '@/api/user'
|
||||
// 移除了 FileAPI 导入,该模块不存在
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
|
||||
definePage({
|
||||
name: 'profile',
|
||||
style: {
|
||||
navigationBarTitleText: '个人中心',
|
||||
},
|
||||
})
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const originalSrc = ref<string>('') // 选取的原图路径
|
||||
const avatarShow = ref<boolean>(false) // 显示头像裁剪
|
||||
const userProfile = ref<UserInfo>() // 用户信息
|
||||
|
||||
/** 加载用户信息 */
|
||||
async function loadUserProfile() {
|
||||
userProfile.value = await UserAPI.getCurrentUserInfo()
|
||||
}
|
||||
|
||||
// 头像选择
|
||||
function avatarUpload() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
originalSrc.value = res.tempFilePaths[0]
|
||||
avatarShow.value = true
|
||||
},
|
||||
})
|
||||
}
|
||||
// 头像裁剪完成
|
||||
function handleAvatarConfirm(event: any) {
|
||||
const { tempFilePath } = event
|
||||
// 使用 UserAPI 的头像上传方法
|
||||
UserAPI.uploadCurrentUserAvatar({ file: tempFilePath }).then(
|
||||
(fileInfo: UploadFileResult) => {
|
||||
const avatarForm = {
|
||||
name: userProfile.value?.name || '',
|
||||
gender: userProfile.value?.gender || '0',
|
||||
mobile: userProfile.value?.mobile || '',
|
||||
email: userProfile.value?.email || '',
|
||||
username: userProfile.value?.username || '',
|
||||
dept_name: userProfile.value?.dept_name || '',
|
||||
positions: userProfile.value?.positions || [],
|
||||
roles: userProfile.value?.roles || [],
|
||||
avatar: fileInfo.file_url,
|
||||
created_at: userProfile.value?.created_at || '',
|
||||
}
|
||||
// 头像路径保存至后端
|
||||
UserAPI.updateCurrentUserInfo(avatarForm).then(() => {
|
||||
uni.showToast({ title: '头像上传成功', icon: 'none' })
|
||||
loadUserProfile()
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// 本页面中所有的校验规则
|
||||
const rules: FormRules = {
|
||||
name: [{ required: true, message: '请填写昵称' }],
|
||||
gender: [{ required: true, message: '请选择性别' }],
|
||||
}
|
||||
|
||||
const dialog = reactive<{
|
||||
visible: boolean
|
||||
title?: string
|
||||
field?: string
|
||||
}>({
|
||||
visible: false,
|
||||
})
|
||||
|
||||
const userProfileForm = reactive<{
|
||||
name?: string
|
||||
gender?: string
|
||||
}>({})
|
||||
const userProfileFormRef = ref()
|
||||
|
||||
// 打开弹窗
|
||||
function handleOpenDialog(field: string) {
|
||||
dialog.field = field
|
||||
dialog.visible = true
|
||||
|
||||
// 初始化表单数据
|
||||
if (field === 'name') {
|
||||
dialog.title = '编辑昵称'
|
||||
userProfileForm.name = userProfile.value?.name || ''
|
||||
}
|
||||
else if (field === 'gender') {
|
||||
dialog.title = '选择性别'
|
||||
userProfileForm.gender = userProfile.value?.gender || '0'
|
||||
}
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
function handleSubmit() {
|
||||
userProfileFormRef.value.validate().then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
UserAPI.updateCurrentUserInfo({
|
||||
name: userProfileForm.name,
|
||||
gender: userProfileForm.gender,
|
||||
mobile: userProfile.value?.mobile || '',
|
||||
email: userProfile.value?.email || '',
|
||||
username: userProfile.value?.username || '',
|
||||
dept_name: userProfile.value?.dept_name || '',
|
||||
positions: userProfile.value?.positions || [],
|
||||
roles: userProfile.value?.roles || [],
|
||||
avatar: userProfile.value?.avatar || '',
|
||||
created_at: userProfile.value?.created_at || '',
|
||||
}).then(() => {
|
||||
uni.showToast({ title: '账号资料修改成功', icon: 'none' })
|
||||
dialog.visible = false
|
||||
loadUserProfile()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 检查登录状态
|
||||
onLoad(() => {
|
||||
if (!userStore.checkLogin())
|
||||
return
|
||||
|
||||
// #ifdef H5
|
||||
document.addEventListener('touchstart', touchstartListener, {
|
||||
passive: false,
|
||||
})
|
||||
document.addEventListener('touchmove', touchmoveListener, { passive: false })
|
||||
// #endif
|
||||
loadUserProfile()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 在onMounted中不再重复检查登录状态和加载用户信息
|
||||
// 如果需要检查登录状态和加载用户信息,请使用onLoad中的逻辑
|
||||
})
|
||||
|
||||
// 页面销毁前移除事件监听
|
||||
onBeforeUnmount(() => {
|
||||
// #ifdef H5
|
||||
document.removeEventListener('touchstart', touchstartListener)
|
||||
document.removeEventListener('touchmove', touchmoveListener)
|
||||
// #endif
|
||||
})
|
||||
// 禁用浏览器双指缩放,使头像裁剪时双指缩放能够起作用
|
||||
function touchstartListener(event: TouchEvent) {
|
||||
if (event.touches.length > 1) {
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
// 禁用浏览器下拉刷新,使头像裁剪时能够移动图片
|
||||
function touchmoveListener(event: TouchEvent) {
|
||||
event.preventDefault()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="app-container">
|
||||
<wd-card
|
||||
v-if="userProfile"
|
||||
custom-style="margin-top: 20rpx"
|
||||
class="theme-card"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-cell
|
||||
class="avatar-cell"
|
||||
title="头像"
|
||||
center
|
||||
is-link
|
||||
@click="avatarUpload"
|
||||
>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
头像
|
||||
</text>
|
||||
</template>
|
||||
<view class="avatar flex-center">
|
||||
<view
|
||||
v-if="!userProfile.avatar"
|
||||
class="img flex-center"
|
||||
@click="avatarUpload"
|
||||
>
|
||||
<wd-icon
|
||||
name="fill-camera"
|
||||
custom-class="img-icon"
|
||||
/>
|
||||
</view>
|
||||
<wd-img
|
||||
v-if="userProfile.avatar"
|
||||
round
|
||||
width="80px"
|
||||
height="80px"
|
||||
:src="userProfile.avatar"
|
||||
mode="aspectFit"
|
||||
custom-class="profile-img"
|
||||
@click="avatarUpload"
|
||||
/>
|
||||
</view>
|
||||
</wd-cell>
|
||||
<wd-cell
|
||||
title="昵称"
|
||||
:value="userProfile.name"
|
||||
is-link
|
||||
@click="handleOpenDialog('name')"
|
||||
>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
昵称
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.name || "未设置"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell
|
||||
title="性别"
|
||||
:value="
|
||||
userProfile.gender === '0'
|
||||
? '男'
|
||||
: userProfile.gender === '1'
|
||||
? '女'
|
||||
: '未知'
|
||||
"
|
||||
is-link
|
||||
@click="handleOpenDialog('gender')"
|
||||
>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
性别
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.gender === "0"
|
||||
? "男"
|
||||
: userProfile.gender === "1"
|
||||
? "女"
|
||||
: "未知"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell title="用户名" :value="userProfile.username">
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
用户名
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{ userProfile.username }}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell v-if="userProfile" title="状态" center>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
状态
|
||||
</text>
|
||||
</template>
|
||||
<wd-tag :type="userProfile.status ? 'success' : 'danger'">
|
||||
{{ userProfile.status ? "启用" : "停用" }}
|
||||
</wd-tag>
|
||||
</wd-cell>
|
||||
<wd-cell v-if="userProfile" title="是否超管" center>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
是否超管
|
||||
</text>
|
||||
</template>
|
||||
<wd-tag
|
||||
plain
|
||||
:type="userProfile.is_superuser ? 'primary' : 'default'"
|
||||
>
|
||||
{{ userProfile.is_superuser ? "是" : "否" }}
|
||||
</wd-tag>
|
||||
</wd-cell>
|
||||
<wd-cell title="手机号" :value="userProfile.mobile">
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
手机号
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.mobile || "未绑定"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell title="邮箱" :value="userProfile.email">
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
邮箱
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.email || "未绑定"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell title="部门" :value="userProfile.dept_name">
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
部门
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.dept_name || "未分配"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell
|
||||
title="角色"
|
||||
:value="userProfile.roles?.map((item) => item.name).join(', ')"
|
||||
>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
角色
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.roles?.map((item) => item.name).join(", ")
|
||||
|| "未分配"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell
|
||||
title="岗位"
|
||||
:value="userProfile.positions?.map((item) => item.name).join(', ')"
|
||||
>
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
岗位
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.positions?.map((item) => item.name).join(", ")
|
||||
|| "未分配"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell title="备注" :value="userProfile.description">
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
备注
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.description || "无"
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell title="创建日期" :value="userProfile.created_at">
|
||||
<template #title>
|
||||
<text class="theme-text-primary">
|
||||
创建日期
|
||||
</text>
|
||||
</template>
|
||||
<template #value>
|
||||
<text class="theme-text-secondary">
|
||||
{{
|
||||
userProfile.created_at
|
||||
}}
|
||||
</text>
|
||||
</template>
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</wd-card>
|
||||
|
||||
<!-- 头像裁剪 -->
|
||||
<wd-img-cropper
|
||||
v-model="avatarShow"
|
||||
:img-src="originalSrc"
|
||||
@confirm="handleAvatarConfirm"
|
||||
/>
|
||||
|
||||
<!-- 用户信息编辑弹出框 -->
|
||||
<wd-popup
|
||||
v-model="dialog.visible"
|
||||
position="bottom"
|
||||
custom-style="border-top-left-radius: 16rpx; border-top-right-radius: 16rpx;"
|
||||
>
|
||||
<view class="popup-header">
|
||||
<wd-cell :title="dialog.title" center>
|
||||
<template #right-icon>
|
||||
<wd-icon name="close" size="20" @click="dialog.visible = false" />
|
||||
</template>
|
||||
</wd-cell>
|
||||
</view>
|
||||
|
||||
<wd-divider />
|
||||
|
||||
<wd-form
|
||||
ref="userProfileFormRef"
|
||||
:model="userProfileForm"
|
||||
custom-class="edit-form"
|
||||
>
|
||||
<wd-cell-group border>
|
||||
<wd-input
|
||||
v-if="dialog.field === 'name'"
|
||||
v-model="userProfileForm.name"
|
||||
label="昵称"
|
||||
label-width="160rpx"
|
||||
placeholder="请输入昵称"
|
||||
prop="name"
|
||||
:rules="rules.name"
|
||||
/>
|
||||
<wd-cell
|
||||
v-if="dialog.field === 'gender'"
|
||||
title="性别"
|
||||
title-width="160rpx"
|
||||
center
|
||||
prop="gender"
|
||||
:rules="rules.gender"
|
||||
>
|
||||
<wd-radio-group
|
||||
v-model="userProfileForm.gender"
|
||||
shape="button"
|
||||
class="ef-radio-group"
|
||||
>
|
||||
<wd-radio :value="0">
|
||||
男
|
||||
</wd-radio>
|
||||
<wd-radio :value="1">
|
||||
女
|
||||
</wd-radio>
|
||||
<wd-radio :value="2">
|
||||
未知
|
||||
</wd-radio>
|
||||
</wd-radio-group>
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
<view>
|
||||
<wd-button type="primary" block @click="handleSubmit">
|
||||
提交
|
||||
</wd-button>
|
||||
</view>
|
||||
</wd-form>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avatar-cell {
|
||||
:deep(.wd-cell__body) {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: right;
|
||||
|
||||
.img {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 50%;
|
||||
|
||||
.img-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-form {
|
||||
padding-top: 40rpx;
|
||||
|
||||
.ef-radio-group {
|
||||
line-height: 1;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,290 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'request',
|
||||
style: {
|
||||
navigationBarTitleText: '网络请求',
|
||||
},
|
||||
})
|
||||
|
||||
const GlobalToast = useGlobalToast()
|
||||
|
||||
// Alova 核心特性
|
||||
const alovaFeatures = [
|
||||
{
|
||||
icon: '⚡',
|
||||
title: '简单易用',
|
||||
description: '观看视频5分钟上手',
|
||||
details: '极简的API设计,直观的使用方式,让开发者快速掌握并投入使用',
|
||||
color: 'blue',
|
||||
},
|
||||
{
|
||||
icon: '🔧',
|
||||
title: '完美兼容',
|
||||
description: '兼容你最喜欢的技术栈',
|
||||
details: '支持Vue、React、Angular等主流框架,以及各种HTTP客户端库',
|
||||
color: 'green',
|
||||
},
|
||||
{
|
||||
icon: '🚀',
|
||||
title: '高性能模块',
|
||||
description: '20+ 高性能的业务模块',
|
||||
details: '提供分页、实时数据、文件上传下载等开箱即用的高性能解决方案',
|
||||
color: 'purple',
|
||||
},
|
||||
{
|
||||
icon: '🔗',
|
||||
title: 'OpenAPI 解决方案',
|
||||
description: '更先进的 openAPI 解决方案',
|
||||
details: '在代码中和API信息高效交互,自动生成类型定义和请求函数',
|
||||
color: 'orange',
|
||||
},
|
||||
{
|
||||
icon: '📦',
|
||||
title: '请求共享缓存',
|
||||
description: '请求共享和响应缓存',
|
||||
details: '智能的请求去重和响应缓存机制,显著提升应用性能',
|
||||
color: 'cyan',
|
||||
},
|
||||
{
|
||||
icon: '🛡️',
|
||||
title: '类型安全',
|
||||
description: '完整的 TypeScript 支持',
|
||||
details: '从请求到响应的全链路类型安全,减少运行时错误',
|
||||
color: 'red',
|
||||
},
|
||||
]
|
||||
|
||||
// 使用真正的 useRequest hook - 获取宠物列表
|
||||
const {
|
||||
data: petData,
|
||||
loading: petLoading,
|
||||
error: petError,
|
||||
send: loadPetData,
|
||||
} = useRequest(
|
||||
(status: 'available' | 'pending' | 'sold' = 'available') => Apis.pet.findPetsByStatus({
|
||||
params: { status },
|
||||
}),
|
||||
{
|
||||
immediate: false,
|
||||
},
|
||||
).onError((error) => {
|
||||
GlobalToast.error(error.error?.message || '获取宠物列表失败')
|
||||
})
|
||||
|
||||
// 使用真正的 useRequest hook - 用户登录演示
|
||||
const {
|
||||
data: loginData,
|
||||
loading: loginLoading,
|
||||
error: loginError,
|
||||
send: performLogin,
|
||||
} = useRequest(
|
||||
(username: string, password: string) => Apis.user.loginUser({
|
||||
params: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
}),
|
||||
{
|
||||
immediate: false,
|
||||
},
|
||||
).onError((error) => {
|
||||
GlobalToast.error(error.error?.message || '用户登录失败')
|
||||
})
|
||||
|
||||
// useRequest 演示函数
|
||||
function demoLoadPets() {
|
||||
loadPetData('available')
|
||||
}
|
||||
|
||||
function demoLogin() {
|
||||
performLogin('testuser', 'testpass')
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
GlobalToast.success(`${url} 已复制到剪贴板`)
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🌐
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
Alova 网络请求
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
极致高效的请求工具集
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
alova完美兼容你最喜欢的HTTP client和UI框架,快速开发客户端和服务的应用的业务逻辑,同时让API信息与代码进行交互,像虫洞一样拉近后端协作距离,极致高效地集成你的APIs
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Alova 核心特性 -->
|
||||
<demo-block title="Alova 核心特性" transparent>
|
||||
<view class="grid grid-cols-2 gap-3">
|
||||
<view
|
||||
v-for="feature in alovaFeatures"
|
||||
:key="feature.title"
|
||||
class="rounded-2 bg-white p-3 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-2 flex items-center">
|
||||
<view class="mr-2 text-5">
|
||||
{{ feature.icon }}
|
||||
</view>
|
||||
<view class="flex-1">
|
||||
<view class="text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ feature.title }}
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
{{ feature.description }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- Alova useRequest 演示 -->
|
||||
<demo-block title="useRequest Hook 演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<!-- 宠物列表请求 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-5">
|
||||
🐾
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
宠物列表请求
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
使用 useRequest 获取宠物列表,支持参数传递和错误处理
|
||||
</view>
|
||||
|
||||
<view class="mb-3">
|
||||
<wd-button
|
||||
type="primary"
|
||||
block
|
||||
:loading="petLoading"
|
||||
@click="demoLoadPets"
|
||||
>
|
||||
获取宠物列表
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<!-- 请求状态显示 -->
|
||||
<view class="space-y-2">
|
||||
<view v-if="petLoading" class="flex items-center text-3 text-blue-600">
|
||||
<wd-icon name="loading" size="14px" class="mr-1" />
|
||||
正在加载宠物数据...
|
||||
</view>
|
||||
<view v-if="petError" class="text-3 text-red-600">
|
||||
❌ 请求失败: {{ petError.message }}
|
||||
</view>
|
||||
<view v-if="petData && !petLoading" class="text-3 text-green-600">
|
||||
✅ 成功获取 {{ petData.length }} 只宠物数据
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 代码示例 -->
|
||||
<view class="mt-3 rounded-2 bg-gray-50 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
代码示例:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
const { data, loading, send } = useRequest(\n
|
||||
(status) => Apis.pet.findPetsByStatus({ params: { status } }),\n
|
||||
{ immediate: false }\n
|
||||
).onError((error) => { ... })
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户登录请求 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 flex items-center">
|
||||
<view class="mr-2 text-5">
|
||||
👤
|
||||
</view>
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
用户登录请求
|
||||
</view>
|
||||
</view>
|
||||
<view class="mb-3 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
演示多参数传递和POST请求处理
|
||||
</view>
|
||||
|
||||
<view class="mb-3">
|
||||
<wd-button
|
||||
type="warning"
|
||||
block
|
||||
:loading="loginLoading"
|
||||
@click="demoLogin"
|
||||
>
|
||||
模拟用户登录
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<!-- 请求状态显示 -->
|
||||
<view class="space-y-2">
|
||||
<view v-if="loginLoading" class="flex items-center text-3 text-blue-600">
|
||||
<wd-icon name="loading" size="14px" class="mr-1" />
|
||||
正在登录中...
|
||||
</view>
|
||||
<view v-if="loginError" class="text-3 text-red-600">
|
||||
❌ 登录失败: {{ loginError.message }}
|
||||
</view>
|
||||
<view v-if="loginData && !loginLoading" class="text-3 text-green-600">
|
||||
✅ 登录成功!
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 代码示例 -->
|
||||
<view class="mt-3 rounded-2 bg-gray-50 p-3 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="mb-2 text-3 text-gray-700 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
代码示例:
|
||||
</view>
|
||||
<view class="text-2.5 text-gray-600 leading-relaxed font-mono dark:text-[var(--wot-dark-color2)]">
|
||||
const { data, loading, send } = useRequest(\n
|
||||
(username, password) => Apis.user.loginUser({\n
|
||||
params: { username, password }\n
|
||||
}),\n
|
||||
{ immediate: false }\n
|
||||
).onError((error) => { ... })
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📚 Alova 官方文档" value="alova.js.org" is-link @click="handleNavigate('https://alova.js.org/')" />
|
||||
<wd-cell title="🐙 GitHub 仓库" value="alovajs/alova" is-link @click="handleNavigate('https://github.com/alovajs/alova')" />
|
||||
<wd-cell title="📖 uni-app 文档" value="网络请求" is-link @click="handleNavigate('https://uniapp.dcloud.net.cn/api/request/request.html')" />
|
||||
<wd-cell title="🎯 Alova Hooks" value="请求策略" is-link @click="handleNavigate('https://alova.js.org/zh-CN/tutorial/client/strategy/')" />
|
||||
<wd-cell title="💡 最佳实践" value="使用指南" is-link @click="handleNavigate('https://alova.js.org/zh-CN/tutorial/project/best-practice/')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-aftereach',
|
||||
style: {
|
||||
navigationBarTitleText: 'afterEach 钩子演示',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
📊
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
afterEach 钩子演示
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
这个页面用于演示 afterEach 钩子的触发
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容 -->
|
||||
<demo-block title="afterEach 演示成功" transparent>
|
||||
<view class="border border-green-200 rounded-2 bg-green-50 p-4 dark:bg-green-900/20">
|
||||
<view class="mb-2 text-4 text-green-700 font-bold dark:text-green-300">
|
||||
🎉 恭喜!
|
||||
</view>
|
||||
<view class="text-3.5 text-green-600 leading-relaxed dark:text-green-200">
|
||||
如果你能看到这个页面,说明 afterEach 钩子已经触发了!\n
|
||||
打开浏览器控制台(F12 → Console)可以看到相关的日志输出。\n
|
||||
afterEach 钩子常用于页面统计、埋点上报等导航后处理。
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="导航" transparent>
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,83 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-guard',
|
||||
style: {
|
||||
navigationBarTitleText: '导航守卫演示',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 演示权限拦截
|
||||
function handleBeforeEach() {
|
||||
router.push({
|
||||
name: 'demo-protected',
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到afterEach演示页面
|
||||
function demoAfterEachPage() {
|
||||
router.push('/subPages/router/demo-aftereach')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
🛡️
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
导航守卫演示
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
演示 beforeEach 和 afterEach 守卫功能
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 守卫演示 -->
|
||||
<demo-block title="守卫演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
前置导航守卫拦截
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
跳转前交互,可以拦截导航
|
||||
</view>
|
||||
<wd-button type="error" block @click="handleBeforeEach">
|
||||
📊 beforeEach 演示
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
后置导航钩子演示
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
跳转到专门的 afterEach 演示页面,体验页面统计、埋点上报等功能
|
||||
</view>
|
||||
<wd-button type="success" block @click="demoAfterEachPage">
|
||||
📊 afterEach 演示
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="导航" transparent>
|
||||
<view class="px-3">
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</view>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,123 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-object',
|
||||
style: {
|
||||
navigationBarTitleText: '对象路径跳转',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
function pushToParams() {
|
||||
router.push({ name: 'demo-params', params: { username: 'eduardo' } })
|
||||
}
|
||||
|
||||
function pushToQuery() {
|
||||
router.push({ path: '/subPages/router/demo-query', query: { keyword: 'vue', type: 'framework' } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
🎯
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
对象路径跳转演示
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
使用 router.push({ path: '/path' }) 进行跳转
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 跳转信息 -->
|
||||
<demo-block title="跳转信息" transparent>
|
||||
<view class="rounded-3 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
当前页面信息
|
||||
</view>
|
||||
<view class="space-y-2">
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
路径:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.path }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
跳转方式:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 dark:text-[var(--wot-dark-color)]">
|
||||
对象路径
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between py-2">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
代码:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push({ path: '/subPages/router/demo-object' })
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 参数传递演示 -->
|
||||
<demo-block title="参数传递演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
params 参数传递
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
使用 name + params 组合传递参数
|
||||
</view>
|
||||
<view class="mb-3 border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push({ name: 'demo-params', params: { username: 'eduardo' } })
|
||||
</text>
|
||||
</view>
|
||||
<wd-button type="primary" block @click="pushToParams">
|
||||
跳转并传递 params
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
query 参数传递
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
使用 path + query 组合传递参数
|
||||
</view>
|
||||
<view class="mb-3 border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push({ path: '/demo-query', query: { keyword: 'vue' } })
|
||||
</text>
|
||||
</view>
|
||||
<wd-button type="success" block @click="pushToQuery">
|
||||
跳转并传递 query
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="导航" transparent>
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-params',
|
||||
style: {
|
||||
navigationBarTitleText: '参数接收演示',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 接收参数
|
||||
const receivedParams = ref({})
|
||||
const decodedUser = ref(null)
|
||||
|
||||
onLoad((option) => {
|
||||
console.log('onLoad option:', option)
|
||||
receivedParams.value = option || {}
|
||||
|
||||
// 如果有user参数,尝试解码对象
|
||||
if (option && option.user) {
|
||||
try {
|
||||
decodedUser.value = JSON.parse(decodeURIComponent(decodeURIComponent(option.user)))
|
||||
}
|
||||
catch (e) {
|
||||
console.error('解码user参数失败:', e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
function pushToGuard() {
|
||||
router.push('/subPages/router/demo-guard')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
📥
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
params 参数接收演示
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
演示如何接收和处理路由参数
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 路由信息 -->
|
||||
<demo-block title="当前路由信息" transparent>
|
||||
<view class="rounded-3 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="space-y-2">
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
路径:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.path }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
名称:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.name }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between py-2">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
接收方式:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 dark:text-[var(--wot-dark-color)]">
|
||||
onLoad(option)
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 参数信息 -->
|
||||
<demo-block title="接收到的参数" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
原始参数 (option)
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(receivedParams, null, 2) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="decodedUser" class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
解码后的对象参数
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(decodedUser, null, 2) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="mt-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
使用 JSON.parse(decodeURIComponent(decodeURIComponent(option.user))) 解码
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- API 说明 -->
|
||||
<demo-block title="API 说明" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
Params vs Query 的区别
|
||||
</view>
|
||||
<view class="mb-3 border border-orange-200 rounded-2 bg-orange-50 p-3 dark:bg-orange-900/20">
|
||||
<view class="mb-2 text-3.5 text-orange-700 font-bold dark:text-orange-300">
|
||||
⚠️ 重要说明
|
||||
</view>
|
||||
<view class="text-3 text-orange-600 leading-relaxed dark:text-orange-200">
|
||||
在 @wot-ui/router 中,params 和 query 参数在实际效果上并无区别,都会以查询字符串形式放在 URL 中。这种 API 设计主要是为了与 vue-router 保持一致。
|
||||
</view>
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 leading-relaxed font-mono dark:text-[var(--wot-dark-color)]">
|
||||
// Params 写法 (当前演示)
|
||||
router.push({ name: 'demo-params', params: { username: 'eduardo' } })
|
||||
// 结果: /demo-params?username=eduardo
|
||||
|
||||
// Query 写法 (效果相同)
|
||||
router.push({ path: '/demo-params', query: { username: 'eduardo' } })
|
||||
// 结果: /demo-params?username=eduardo
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 代码示例 -->
|
||||
<demo-block title="代码示例" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
接收参数的标准写法
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 leading-relaxed font-mono dark:text-[var(--wot-dark-color)]">
|
||||
onLoad((option) => {
|
||||
if (option && option.username) {
|
||||
const username = option.username
|
||||
}
|
||||
|
||||
// 对象参数需要解码
|
||||
if (option && option.user) {
|
||||
const user = JSON.parse(decodeURIComponent(decodeURIComponent(option.user)))
|
||||
}
|
||||
})
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="继续演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<wd-button type="primary" block @click="pushToGuard">
|
||||
跳转到导航守卫演示
|
||||
</wd-button>
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</view>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-protected',
|
||||
style: {
|
||||
navigationBarTitleText: '受保护页面',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
🔒
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
受保护的页面
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
这个页面被路由守卫保护,只有登录用户才能访问
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容 -->
|
||||
<demo-block title="守卫拦截成功" transparent>
|
||||
<view class="border border-green-200 rounded-2 bg-green-50 p-4 dark:bg-green-900/20">
|
||||
<view class="mb-2 text-4 text-green-700 font-bold dark:text-green-300">
|
||||
🎉 恭喜!
|
||||
</view>
|
||||
<view class="text-3.5 text-green-600 leading-relaxed dark:text-green-200">
|
||||
如果你能看到这个页面,说明路由守卫验证通过了!\n
|
||||
但实际上,这个页面被配置为需要登录才能访问,\n
|
||||
守卫应该会拦截并重定向你到首页。
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="导航" transparent>
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,201 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-query',
|
||||
style: {
|
||||
navigationBarTitleText: '查询参数接收演示',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 接收参数
|
||||
const receivedQuery = ref({})
|
||||
const decodedUser = ref(null)
|
||||
|
||||
onLoad((option) => {
|
||||
console.log('onLoad option:', option)
|
||||
receivedQuery.value = option || {}
|
||||
|
||||
// 如果有user参数,尝试解码对象
|
||||
if (option && option.user) {
|
||||
try {
|
||||
decodedUser.value = JSON.parse(decodeURIComponent(decodeURIComponent(option.user)))
|
||||
}
|
||||
catch (e) {
|
||||
console.error('解码user参数失败:', e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
function pushToGuard() {
|
||||
router.push('/subPages/router/demo-guard')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
📨
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
query 参数接收演示
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
演示如何接收和处理查询参数
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 路由信息 -->
|
||||
<demo-block title="当前路由信息" transparent>
|
||||
<view class="rounded-3 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="space-y-2">
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
路径:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.path }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
查询字符串:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(route.query) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between py-2">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
接收方式:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 dark:text-[var(--wot-dark-color)]">
|
||||
onLoad(option)
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 参数信息 -->
|
||||
<demo-block title="接收到的查询参数" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
原始查询参数 (option)
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(receivedQuery, null, 2) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="mt-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
URL: /demo-query?keyword={{ (receivedQuery as any).keyword }}&type={{ (receivedQuery as any).type }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="decodedUser" class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
解码后的对象参数
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(decodedUser, null, 2) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="mt-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
使用 JSON.parse(decodeURIComponent(decodeURIComponent(option.user))) 解码
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- Query vs Params 说明 -->
|
||||
<demo-block title="Query vs Params 说明" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
两种参数传递方式说明
|
||||
</view>
|
||||
<view class="mb-3 border border-orange-200 rounded-2 bg-orange-50 p-3 dark:bg-orange-900/20">
|
||||
<view class="mb-2 text-3.5 text-orange-700 font-bold dark:text-orange-300">
|
||||
⚠️ 重要说明
|
||||
</view>
|
||||
<view class="text-3 text-orange-600 leading-relaxed dark:text-orange-200">
|
||||
在 @wot-ui/router 中,query 和 params 参数都会放在 URL 中,两者在实际效果上并无区别。这种 API 设计主要是为了与 vue-router 保持一致。
|
||||
</view>
|
||||
</view>
|
||||
<view class="space-y-3">
|
||||
<view class="border border-blue-200 rounded-2 bg-blue-50 p-3 dark:bg-blue-900/20">
|
||||
<view class="mb-2 text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
Query 写法 (当前演示)
|
||||
</view>
|
||||
<view class="text-3 text-blue-600 leading-relaxed dark:text-blue-200">
|
||||
• 使用 path + query 组合\n
|
||||
• 参数以查询字符串形式出现\n
|
||||
• 写法: router.push({ path: '/page', query: { key: 'value' } })\n
|
||||
• 结果: /page?key=value
|
||||
</view>
|
||||
</view>
|
||||
<view class="border border-green-200 rounded-2 bg-green-50 p-3 dark:bg-green-900/20">
|
||||
<view class="mb-2 text-3.5 text-green-700 font-bold dark:text-green-300">
|
||||
Params 写法
|
||||
</view>
|
||||
<view class="text-3 text-green-600 leading-relaxed dark:text-green-200">
|
||||
• 使用 name + params 组合\n
|
||||
• 参数同样以查询字符串形式出现\n
|
||||
• 写法: router.push({ name: 'page', params: { key: 'value' } })\n
|
||||
• 结果: /page?key=value (效果相同)
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 代码示例 -->
|
||||
<demo-block title="代码示例" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
接收查询参数的标准写法
|
||||
</view>
|
||||
<view class="border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]">
|
||||
<text class="text-3 text-gray-700 leading-relaxed font-mono dark:text-[var(--wot-dark-color)]">
|
||||
// 发送方
|
||||
router.push({
|
||||
path: '/demo-query',
|
||||
query: { keyword: 'vue', type: 'framework' }
|
||||
})
|
||||
|
||||
// 接收方
|
||||
onLoad((option) => {
|
||||
if (option && option.keyword) {
|
||||
const keyword = option.keyword // 'vue'
|
||||
const type = option.type // 'framework'
|
||||
}
|
||||
})
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="继续演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<wd-button type="primary" block @click="pushToGuard">
|
||||
跳转到导航守卫演示
|
||||
</wd-button>
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</view>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,85 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'demo-string',
|
||||
style: {
|
||||
navigationBarTitleText: '字符串路径跳转',
|
||||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
function goBack() {
|
||||
router.back()
|
||||
}
|
||||
|
||||
function pushToObject() {
|
||||
router.push({ path: '/subPages/router/demo-object' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-6 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-8">
|
||||
📝
|
||||
</view>
|
||||
<view class="mb-2 text-5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
字符串路径跳转演示
|
||||
</view>
|
||||
<view class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
使用 router.push('/path') 进行跳转
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 跳转信息 -->
|
||||
<demo-block title="跳转信息" transparent>
|
||||
<view class="rounded-3 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
当前页面信息
|
||||
</view>
|
||||
<view class="space-y-2">
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
路径:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.path }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
跳转方式:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 dark:text-[var(--wot-dark-color)]">
|
||||
字符串路径
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between py-2">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
代码:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push('/subPages/router/demo-string')
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<demo-block title="继续演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<wd-button type="primary" block @click="pushToObject">
|
||||
跳转到对象路径演示
|
||||
</wd-button>
|
||||
<wd-button type="warning" block @click="goBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</view>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,469 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'router',
|
||||
style: {
|
||||
navigationBarTitleText: '路由管理',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 表单数据
|
||||
const userId = ref('eduardo')
|
||||
const searchKeyword = ref('vue')
|
||||
const userName = ref('小星星')
|
||||
const userLabel = ref('小熊熊')
|
||||
|
||||
// 基础导航方法
|
||||
function pushByString() {
|
||||
// 字符串路径
|
||||
router.push('/subPages/router/demo-string')
|
||||
showSuccess({ msg: '使用字符串路径跳转' })
|
||||
}
|
||||
|
||||
function pushByPath() {
|
||||
// 带有路径的对象
|
||||
router.push({ path: '/subPages/router/demo-object' })
|
||||
showSuccess({ msg: '使用path对象跳转' })
|
||||
}
|
||||
|
||||
function pushByName() {
|
||||
// 命名的路由
|
||||
router.push({ name: 'demo-object' })
|
||||
showSuccess({ msg: '使用name跳转' })
|
||||
}
|
||||
|
||||
// 参数传递示例
|
||||
function pushWithParams() {
|
||||
if (!userId.value) {
|
||||
uni.showToast({
|
||||
title: '请输入用户ID',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
// 命名的路由,并加上参数
|
||||
router.push({ name: 'demo-params', params: { username: userId.value } })
|
||||
showSuccess({ msg: `传递参数: ${userId.value}` })
|
||||
}
|
||||
|
||||
function pushWithQuery() {
|
||||
if (!searchKeyword.value) {
|
||||
uni.showToast({
|
||||
title: '请输入搜索关键词',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
// 带查询参数
|
||||
router.push({ path: '/subPages/router/demo-query', query: { username: searchKeyword.value } })
|
||||
showSuccess({ msg: `传递查询参数: ${searchKeyword.value}` })
|
||||
}
|
||||
|
||||
// 传递对象参数
|
||||
function pushWithObjectParams() {
|
||||
const user = {
|
||||
name: userName.value,
|
||||
label: userLabel.value,
|
||||
}
|
||||
// 命名路由传递对象参数
|
||||
router.push({
|
||||
name: 'demo-params',
|
||||
params: { user: encodeURIComponent(JSON.stringify(user)) },
|
||||
})
|
||||
showSuccess({ msg: '传递对象参数(params)' })
|
||||
}
|
||||
|
||||
function pushWithObjectQuery() {
|
||||
const user = {
|
||||
name: userName.value,
|
||||
label: userLabel.value,
|
||||
}
|
||||
// path+query传递对象参数
|
||||
router.push({
|
||||
path: '/subPages/router/demo-query',
|
||||
query: { user: encodeURIComponent(JSON.stringify(user)) },
|
||||
})
|
||||
showSuccess({ msg: '传递对象参数(query)' })
|
||||
}
|
||||
|
||||
// 导航守卫演示
|
||||
function demoNavigationGuards() {
|
||||
showSuccess({ msg: '跳转到完整的导航守卫演示页面' })
|
||||
router.push({
|
||||
name: 'demo-guard',
|
||||
})
|
||||
}
|
||||
|
||||
// Router方法演示
|
||||
function demoPush() {
|
||||
router.push('/subPages/router/demo-string')
|
||||
showSuccess({ msg: 'router.push() - 保留当前页面跳转' })
|
||||
}
|
||||
|
||||
function demoPushTab() {
|
||||
router.pushTab('/pages/index/index')
|
||||
showSuccess({ msg: 'router.pushTab() - 跳转到tabBar页面' })
|
||||
}
|
||||
|
||||
function demoReplace() {
|
||||
router.replace('/subPages/router/demo-object')
|
||||
showSuccess({ msg: 'router.replace() - 替换当前页面' })
|
||||
}
|
||||
|
||||
function demoReplaceAll() {
|
||||
router.replaceAll('/pages/index/index')
|
||||
showSuccess({ msg: 'router.replaceAll() - 关闭所有页面重新开始' })
|
||||
}
|
||||
|
||||
function demoBack() {
|
||||
router.back()
|
||||
showSuccess({ msg: 'router.back() - 返回上一页' })
|
||||
}
|
||||
|
||||
// 复制代码到剪贴板
|
||||
function copyCode(code: string) {
|
||||
uni.setClipboardData({
|
||||
data: code,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: '代码已复制到剪贴板' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: `${url} 已复制到剪贴板` })
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🚀
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
@wot-ui/router
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
轻量级路由管理解决方案
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
支持编程式导航、参数传递、导航守卫等功能
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 当前路由信息 -->
|
||||
<demo-block title="当前路由信息" transparent>
|
||||
<view class="rounded-3 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 last:border-b-0 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
路径:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.path }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 last:border-b-0 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
名称:
|
||||
</text>
|
||||
<text class="text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ route.name || '未设置' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between border-b border-gray-100 py-2 last:border-b-0 dark:border-[var(--wot-dark-border)]">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
参数:
|
||||
</text>
|
||||
<text class="break-all text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(route.params) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="flex items-center justify-between py-2">
|
||||
<text class="text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
查询:
|
||||
</text>
|
||||
<text class="break-all text-3.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ JSON.stringify(route.query) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 编程式导航 -->
|
||||
<demo-block title="编程式导航" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
基础用法
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.push(\'/user\')')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push('/user')
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="grid grid-cols-1 gap-2">
|
||||
<wd-button type="primary" size="small" @click="pushByString">
|
||||
字符串路径跳转
|
||||
</wd-button>
|
||||
<wd-button type="success" size="small" @click="pushByPath">
|
||||
对象路径跳转
|
||||
</wd-button>
|
||||
<wd-button type="warning" size="small" @click="pushByName">
|
||||
命名路由跳转
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- Router方法演示 -->
|
||||
<demo-block title="Router方法演示" transparent>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
push 方法
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
保留当前页面,跳转到应用内的某个页面,相当于 uni.navigateTo()
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.push(target)')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push(target)
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<wd-button type="primary" block @click="demoPush">
|
||||
演示 push 方法
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
pushTab 方法
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,相当于 uni.switchTab()
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.pushTab(target)')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.pushTab(target)
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<wd-button type="success" block @click="demoPushTab">
|
||||
演示 pushTab 方法
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
replace 方法
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
关闭当前页面,跳转到应用内的某个页面,相当于 uni.redirectTo()
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.replace(target)')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.replace(target)
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<wd-button type="warning" block @click="demoReplace">
|
||||
演示 replace 方法
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
replaceAll 方法
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
关闭所有页面,打开到应用内的某个页面,相当于 uni.reLaunch()
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.replaceAll(target)')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.replaceAll(target)
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<wd-button type="error" block @click="demoReplaceAll">
|
||||
演示 replaceAll 方法
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
back 方法
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
关闭当前页面,返回上一页面或多级页面,相当于 uni.navigateBack()
|
||||
</view>
|
||||
<view class="mb-3 space-y-2">
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.back()')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.back()
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.back({ delta: 2 })')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.back({ delta: 2 })
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
<wd-button type="info" block @click="demoBack">
|
||||
返回上一页
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 参数传递 -->
|
||||
<demo-block title="参数传递" transparent>
|
||||
<view class="mb-3 border border-orange-200 rounded-2 bg-orange-50 p-3 dark:bg-orange-900/20">
|
||||
<view class="mb-2 text-3.5 text-orange-700 font-bold dark:text-orange-300">
|
||||
⚠️ 重要提示
|
||||
</view>
|
||||
<view class="text-3 text-orange-600 leading-relaxed dark:text-orange-200">
|
||||
在 @wot-ui/router 中,params 和 query 参数都会以查询字符串形式放在 URL 中,两者在实际效果上并无区别。这种 API 设计主要是为了与 vue-router 保持一致。
|
||||
</view>
|
||||
</view>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
params 参数
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
注意:name 和 params 搭配使用,与 query 效果相同
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<wd-input v-model="userId" placeholder="请输入用户名" />
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.push({ name: \'user\', params: { username: \'eduardo\' } })')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push({ name: 'user', params: { username: 'eduardo' } })
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<wd-button type="primary" block @click="pushWithParams">
|
||||
传递 params 参数
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
query 参数
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 dark:text-[var(--wot-dark-color2)]">
|
||||
注意:path 可以与 query 一起使用,与 params 效果相同
|
||||
</view>
|
||||
<view class="mb-3">
|
||||
<wd-input v-model="searchKeyword" placeholder="请输入搜索关键词" />
|
||||
</view>
|
||||
<view class="mb-3 flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.push({ path: \'/user\', query: { username: \'eduardo\' } })')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.push({ path: '/user', query: { username: 'eduardo' } })
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<wd-button type="success" block @click="pushWithQuery">
|
||||
传递 query 参数
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
传递对象参数
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
URL有长度限制,复杂对象需要使用 encodeURIComponent 编码
|
||||
</view>
|
||||
<view class="grid grid-cols-2 mb-3 gap-2">
|
||||
<wd-input v-model="userName" placeholder="姓名" />
|
||||
<wd-input v-model="userLabel" placeholder="标签" />
|
||||
</view>
|
||||
<view class="grid grid-cols-2 gap-2">
|
||||
<wd-button type="primary" size="small" @click="pushWithObjectParams">
|
||||
对象 params
|
||||
</wd-button>
|
||||
<wd-button type="success" size="small" @click="pushWithObjectQuery">
|
||||
对象 query
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 导航守卫 -->
|
||||
<demo-block title="导航守卫" transparent>
|
||||
<view class="mb-3 border border-blue-200 rounded-2 bg-blue-50 p-3 dark:bg-blue-900/20">
|
||||
<view class="mb-2 text-3.5 text-blue-700 font-bold dark:text-blue-300">
|
||||
💡 完整演示
|
||||
</view>
|
||||
<view class="text-3 text-blue-600 leading-relaxed dark:text-blue-200">
|
||||
导航守卫功能比较复杂,我们准备了专门的演示页面,包含实时日志、权限验证、参数检查等完整功能演示。
|
||||
</view>
|
||||
</view>
|
||||
<view class="space-y-3">
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
基础守卫 API
|
||||
</view>
|
||||
<view class="mb-3 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
beforeEach 和 afterEach 是最常用的导航守卫
|
||||
</view>
|
||||
<view class="mb-3 space-y-2">
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.beforeEach((to, from, next) => { next() })')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.beforeEach((to, from, next) => { next() })
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
<view class="flex items-center justify-between border border-gray-200 rounded-2 bg-gray-50 p-3 dark:border-[var(--wot-dark-border)] dark:bg-[var(--wot-dark-background3)]" @click="copyCode('router.afterEach((to, from) => { })')">
|
||||
<text class="flex-1 text-3 text-gray-700 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
router.afterEach((to, from) => { console.log(to) })
|
||||
</text>
|
||||
<wd-icon name="copy" size="16px" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
<wd-button type="primary" block @click="demoNavigationGuards">
|
||||
🛡️ 进入完整守卫演示
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📚 @wot-ui/router 文档" value="路由管理" is-link @click="handleNavigate('https://moonofweisheng.github.io/@wot-ui/router/')" />
|
||||
<wd-cell title="🐙 GitHub 仓库" value="@wot-ui/router" is-link @click="handleNavigate('https://my-uni.wot-ui.cn/')" />
|
||||
<wd-cell title="📖 uni-app 路由文档" value="页面路由" is-link @click="handleNavigate('https://uniapp.dcloud.net.cn/tutorial/page.html')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,210 @@
|
||||
<script lang="ts" setup>
|
||||
definePage({
|
||||
name: 'settings',
|
||||
style: {
|
||||
navigationBarTitleText: '系统设置',
|
||||
},
|
||||
})
|
||||
|
||||
// 是否正在清理
|
||||
const clearing = ref(false)
|
||||
// 缓存大小
|
||||
const cacheSize = ref<any>('计算中...')
|
||||
|
||||
const {
|
||||
theme,
|
||||
toggleTheme,
|
||||
currentThemeColor,
|
||||
showThemeColorSheet,
|
||||
themeColorOptions,
|
||||
openThemeColorPicker,
|
||||
closeThemeColorPicker,
|
||||
selectThemeColor,
|
||||
setFollowSystem,
|
||||
} = useManualTheme()
|
||||
|
||||
const isDark = computed({
|
||||
get() {
|
||||
return theme.value === 'dark'
|
||||
},
|
||||
set() {
|
||||
toggleTheme()
|
||||
},
|
||||
})
|
||||
|
||||
// 处理主题色选择
|
||||
function handleThemeColorSelect(option: any) {
|
||||
selectThemeColor(option)
|
||||
}
|
||||
|
||||
// 获取缓存大小
|
||||
async function getCacheSize() {
|
||||
try {
|
||||
// #ifdef MP-WEIXIN
|
||||
const res = await uni.getStorageInfo()
|
||||
cacheSize.value = formatSize(res.currentSize)
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
cacheSize.value = formatSize(
|
||||
Object.keys(localStorage).reduce(
|
||||
(size, key) => size + localStorage[key].length,
|
||||
0,
|
||||
),
|
||||
)
|
||||
// #endif
|
||||
if (!cacheSize.value) {
|
||||
cacheSize.value = '0B'
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取缓存大小失败:', error)
|
||||
cacheSize.value = '获取失败'
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化存储大小
|
||||
function formatSize(size: number) {
|
||||
if (size < 1024) {
|
||||
return `${size}B`
|
||||
}
|
||||
else if (size < 1024 * 1024) {
|
||||
return `${(size / 1024).toFixed(2)}KB`
|
||||
}
|
||||
else {
|
||||
return `${(size / 1024 / 1024).toFixed(2)}MB`
|
||||
}
|
||||
}
|
||||
|
||||
// 处理清除缓存
|
||||
async function handleClearCache() {
|
||||
if (cacheSize.value === '获取失败') {
|
||||
uni.showToast({
|
||||
title: '获取缓存信息失败,请稍后重试',
|
||||
icon: 'none',
|
||||
duration: 2000,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (cacheSize.value === '0B') {
|
||||
uni.showToast({
|
||||
title: '暂无缓存需要清理',
|
||||
icon: 'none',
|
||||
duration: 2000,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (clearing.value) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
clearing.value = true
|
||||
// 模拟清理过程
|
||||
await new Promise(resolve => setTimeout(resolve, 1500))
|
||||
// 清除缓存
|
||||
await uni.clearStorage()
|
||||
// 更新缓存大小显示
|
||||
await getCacheSize()
|
||||
// 提示清理成功
|
||||
uni.showToast({
|
||||
title: '清理成功',
|
||||
icon: 'success',
|
||||
})
|
||||
}
|
||||
catch {
|
||||
uni.showToast({
|
||||
title: '清理失败',
|
||||
icon: 'error',
|
||||
})
|
||||
}
|
||||
finally {
|
||||
clearing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时初始化
|
||||
onLoad(() => {
|
||||
getCacheSize()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="app-container">
|
||||
<demo-block title="基础设置" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="暗黑模式">
|
||||
<wd-switch v-model="isDark" size="18px" />
|
||||
</wd-cell>
|
||||
<wd-cell title="跟随系统">
|
||||
<wd-button size="small" @click="setFollowSystem">
|
||||
跟随系统
|
||||
</wd-button>
|
||||
</wd-cell>
|
||||
<wd-cell title="选择主题色" is-link @click="openThemeColorPicker">
|
||||
<view class="flex items-center justify-end gap-2">
|
||||
<view
|
||||
class="h-4 w-4 rounded-full"
|
||||
:style="{ backgroundColor: currentThemeColor.primary }"
|
||||
/>
|
||||
<text>{{ currentThemeColor.name }}</text>
|
||||
</view>
|
||||
</wd-cell>
|
||||
|
||||
<wd-divider />
|
||||
<wd-cell
|
||||
title="清空缓存"
|
||||
icon="delete1"
|
||||
:value="cacheSize"
|
||||
clickable
|
||||
@click="handleClearCache"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
|
||||
<!-- 主题色选择 ActionSheet -->
|
||||
<wd-action-sheet
|
||||
v-model="showThemeColorSheet"
|
||||
title="选择主题色"
|
||||
:close-on-click-action="true"
|
||||
@cancel="closeThemeColorPicker"
|
||||
>
|
||||
<view class="px-4 pb-4">
|
||||
<view
|
||||
v-for="option in themeColorOptions"
|
||||
:key="option.value"
|
||||
class="flex items-center justify-between border-b border-gray-100 py-3 last:border-b-0 dark:border-gray-700"
|
||||
@click="handleThemeColorSelect(option)"
|
||||
>
|
||||
<view class="flex items-center gap-3">
|
||||
<view
|
||||
class="h-6 w-6 border-2 border-gray-200 rounded-full dark:border-gray-600"
|
||||
:style="{ backgroundColor: option.primary }"
|
||||
/>
|
||||
<text class="text-4 text-gray-800 dark:text-gray-200">
|
||||
{{ option.name }}
|
||||
</text>
|
||||
</view>
|
||||
<wd-icon
|
||||
v-if="currentThemeColor.value === option.value"
|
||||
name="check"
|
||||
:color="option.primary"
|
||||
size="20px"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<wd-gap :height="50" />
|
||||
</wd-action-sheet>
|
||||
|
||||
<!-- 使用wot-design-uni的Loading组件 -->
|
||||
<wd-loading
|
||||
v-if="clearing"
|
||||
v-model="clearing"
|
||||
text="正在清理..."
|
||||
mask
|
||||
custom-class="loading-center"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
@@ -0,0 +1,158 @@
|
||||
<script setup lang="ts">
|
||||
import { useToast } from 'wot-design-uni'
|
||||
|
||||
definePage({
|
||||
name: 'skills',
|
||||
layout: 'default',
|
||||
style: {
|
||||
navigationBarTitleText: 'Agent Skills',
|
||||
navigationBarBackgroundColor: '#f9fafb',
|
||||
navigationBarTextStyle: 'black',
|
||||
},
|
||||
})
|
||||
|
||||
const toast = useToast()
|
||||
|
||||
const skills = [
|
||||
{
|
||||
name: 'alova-api-module',
|
||||
desc: '快速创建 Alova 请求模块和 Mock 数据',
|
||||
icon: 'swap',
|
||||
color: '#007AFF',
|
||||
},
|
||||
{
|
||||
name: 'global-feedback',
|
||||
desc: '全局反馈组件(Toast/Message/Loading)使用指南',
|
||||
icon: 'chat',
|
||||
color: '#34C759',
|
||||
},
|
||||
{
|
||||
name: 'pinia-store-generator',
|
||||
desc: '创建符合项目规范的 Pinia Store',
|
||||
icon: 'folder',
|
||||
color: '#FFCC00',
|
||||
},
|
||||
{
|
||||
name: 'uni-page-generator',
|
||||
desc: '基于项目规范快速生成 uni-app 页面',
|
||||
icon: 'file',
|
||||
color: '#FF9500',
|
||||
},
|
||||
{
|
||||
name: 'vue-composable-creator',
|
||||
desc: '快速创建 Vue 3 组合式函数',
|
||||
icon: 'setting',
|
||||
color: '#5856D6',
|
||||
},
|
||||
{
|
||||
name: 'wot-router-usage',
|
||||
desc: '@wot-ui/router 轻量级路由库使用指南',
|
||||
icon: 'location',
|
||||
color: '#FF2D55',
|
||||
},
|
||||
]
|
||||
|
||||
function handleClick(skill: string) {
|
||||
toast.success(`已选择: ${skill}`)
|
||||
}
|
||||
|
||||
function getIconBg(color: string) {
|
||||
// Simple hex to rgba with low opacity
|
||||
const r = Number.parseInt(color.slice(1, 3), 16)
|
||||
const g = Number.parseInt(color.slice(3, 5), 16)
|
||||
const b = Number.parseInt(color.slice(5, 7), 16)
|
||||
return `rgba(${r}, ${g}, ${b}, 0.1)`
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="pb-safe box-border min-h-screen bg-[#f9fafb]">
|
||||
<!-- Header -->
|
||||
<view class="px-6 pb-6 pt-8">
|
||||
<view class="mb-2 text-3xl text-gray-900 font-bold leading-tight">
|
||||
Agent Skills
|
||||
</view>
|
||||
<view class="text-base text-gray-500 leading-relaxed">
|
||||
利用智能工具赋能开发效率,<br>打造极致开发体验。
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Content -->
|
||||
<view class="px-5 space-y-4">
|
||||
<view
|
||||
v-for="(skill, index) in skills"
|
||||
:key="skill.name"
|
||||
class="group relative animate-fade-in-up overflow-hidden rounded-[24px] bg-white p-5 shadow-sm transition-all duration-300 active:scale-[0.98]"
|
||||
:style="{ animationDelay: `${index * 100}ms` }"
|
||||
@click="handleClick(skill.name)"
|
||||
>
|
||||
<view class="flex items-start gap-4">
|
||||
<!-- Icon Container -->
|
||||
<view
|
||||
class="h-14 w-14 flex shrink-0 items-center justify-center rounded-[18px] transition-transform duration-300 group-active:scale-110"
|
||||
:style="{ backgroundColor: getIconBg(skill.color) }"
|
||||
>
|
||||
<wd-icon
|
||||
:name="skill.icon"
|
||||
size="28px"
|
||||
:color="skill.color"
|
||||
custom-style="display: block;"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- Text Content -->
|
||||
<view class="min-w-0 flex-1 pt-0.5">
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="truncate pr-2 text-lg text-gray-900 font-bold">
|
||||
{{ skill.name }}
|
||||
</view>
|
||||
<wd-icon name="arrow-right" color="#E5E7EB" size="20px" />
|
||||
</view>
|
||||
<view class="line-clamp-2 mt-1 text-sm text-gray-500 leading-relaxed">
|
||||
{{ skill.desc }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Decoration (optional glow or highlight) -->
|
||||
<view
|
||||
class="pointer-events-none absolute h-24 w-24 rounded-full opacity-[0.03] -bottom-4 -right-4"
|
||||
:style="{ backgroundColor: skill.color }"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<wd-toast />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fade-in-up {
|
||||
opacity: 0; /* meaningful for delay */
|
||||
animation: fadeInUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
.line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pb-safe {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,493 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'styles',
|
||||
style: {
|
||||
navigationBarTitleText: 'UnoCSS 演示',
|
||||
},
|
||||
})
|
||||
|
||||
const { success: showSuccess } = useGlobalToast()
|
||||
|
||||
// 演示状态
|
||||
const animationState = ref(false)
|
||||
|
||||
// UnoCSS 核心特性
|
||||
const unocssFeatures = ref([
|
||||
{
|
||||
icon: '⚡',
|
||||
title: '即时按需',
|
||||
desc: '只生成你使用的CSS',
|
||||
example: 'text-red-500 bg-blue-100',
|
||||
},
|
||||
{
|
||||
icon: '🎨',
|
||||
title: '完全可定制',
|
||||
desc: '灵活的配置和预设',
|
||||
example: 'custom-color-brand',
|
||||
},
|
||||
{
|
||||
icon: '🔧',
|
||||
title: '预设丰富',
|
||||
desc: '内置Tailwind、Windi等预设',
|
||||
example: '@unocss/preset-wind',
|
||||
},
|
||||
{
|
||||
icon: '🚀',
|
||||
title: '性能优异',
|
||||
desc: '极快的构建速度',
|
||||
example: '< 200ms',
|
||||
},
|
||||
])
|
||||
|
||||
// 颜色系统演示
|
||||
const colorCategories = ref([
|
||||
{
|
||||
name: '灰色系',
|
||||
colors: [
|
||||
{ name: 'gray-50', class: 'bg-gray-50', value: '#f9fafb' },
|
||||
{ name: 'gray-100', class: 'bg-gray-100', value: '#f3f4f6' },
|
||||
{ name: 'gray-200', class: 'bg-gray-200', value: '#e5e7eb' },
|
||||
{ name: 'gray-300', class: 'bg-gray-300', value: '#d1d5db' },
|
||||
{ name: 'gray-400', class: 'bg-gray-400', value: '#9ca3af' },
|
||||
{ name: 'gray-500', class: 'bg-gray-500', value: '#6b7280' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '主题色',
|
||||
colors: [
|
||||
{ name: 'blue-500', class: 'bg-blue-500', value: '#3b82f6' },
|
||||
{ name: 'green-500', class: 'bg-green-500', value: '#10b981' },
|
||||
{ name: 'red-500', class: 'bg-red-500', value: '#ef4444' },
|
||||
{ name: 'yellow-500', class: 'bg-yellow-500', value: '#f59e0b' },
|
||||
{ name: 'purple-500', class: 'bg-purple-500', value: '#8b5cf6' },
|
||||
{ name: 'pink-500', class: 'bg-pink-500', value: '#ec4899' },
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
// 布局演示数据
|
||||
const layoutExamples = ref([
|
||||
{
|
||||
title: 'Flex 居中',
|
||||
code: 'flex items-center justify-center',
|
||||
class: 'flex items-center justify-center h-20 bg-blue-100 rounded-2 text-blue-800',
|
||||
},
|
||||
{
|
||||
title: 'Grid 网格',
|
||||
code: 'grid grid-cols-3 gap-4',
|
||||
class: 'grid grid-cols-3 gap-2',
|
||||
},
|
||||
{
|
||||
title: 'Space Between',
|
||||
code: 'flex justify-between items-center',
|
||||
class: 'flex justify-between items-center h-16 bg-green-100 rounded-2 px-4 text-green-800',
|
||||
},
|
||||
])
|
||||
|
||||
// 间距系统
|
||||
const spacingExamples = ref([
|
||||
{ name: 'p-1', value: '4px', class: 'p-1 bg-red-100 inline-block m-1 rounded' },
|
||||
{ name: 'p-2', value: '8px', class: 'p-2 bg-blue-100 inline-block m-1 rounded' },
|
||||
{ name: 'p-4', value: '16px', class: 'p-4 bg-green-100 inline-block m-1 rounded' },
|
||||
{ name: 'p-6', value: '24px', class: 'p-6 bg-yellow-100 inline-block m-1 rounded' },
|
||||
{ name: 'p-8', value: '32px', class: 'p-8 bg-purple-100 inline-block m-1 rounded' },
|
||||
])
|
||||
|
||||
// 字体系统
|
||||
const fontExamples = ref([
|
||||
{ name: 'text-xs', size: '12px', class: 'text-xs' },
|
||||
{ name: 'text-sm', size: '14px', class: 'text-sm' },
|
||||
{ name: 'text-base', size: '16px', class: 'text-base' },
|
||||
{ name: 'text-lg', size: '18px', class: 'text-lg' },
|
||||
{ name: 'text-xl', size: '20px', class: 'text-xl' },
|
||||
{ name: 'text-2xl', size: '24px', class: 'text-2xl' },
|
||||
{ name: 'text-3xl', size: '30px', class: 'text-3xl' },
|
||||
])
|
||||
|
||||
// 阴影和效果
|
||||
const effectExamples = ref([
|
||||
{ name: 'shadow-sm', class: 'shadow-sm bg-white p-4 rounded-2 mb-3' },
|
||||
{ name: 'shadow', class: 'shadow bg-white p-4 rounded-2 mb-3' },
|
||||
{ name: 'shadow-md', class: 'shadow-md bg-white p-4 rounded-2 mb-3' },
|
||||
{ name: 'shadow-lg', class: 'shadow-lg bg-white p-4 rounded-2 mb-3' },
|
||||
{ name: 'shadow-xl', class: 'shadow-xl bg-white p-4 rounded-2 mb-3' },
|
||||
])
|
||||
|
||||
// 切换动画
|
||||
function toggleAnimation() {
|
||||
animationState.value = !animationState.value
|
||||
showSuccess({ msg: `动画状态: ${animationState.value ? '开启' : '关闭'}` })
|
||||
}
|
||||
|
||||
// 复制代码
|
||||
function copyCode(code: string) {
|
||||
uni.setClipboardData({
|
||||
data: code,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: '代码已复制到剪贴板' })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 链接导航处理
|
||||
function handleNavigate(url: string) {
|
||||
// #ifdef H5
|
||||
window.open(url, '_blank')
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.setClipboardData({
|
||||
data: url,
|
||||
showToast: false,
|
||||
success: () => {
|
||||
uni.hideToast()
|
||||
showSuccess({ msg: `${url} 已复制到剪贴板` })
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen bg-gray-100 py-3 dark:bg-[var(--wot-dark-background)]">
|
||||
<!-- 头部介绍 -->
|
||||
<view class="mx-3 mb-3">
|
||||
<view class="rounded-3 bg-white px-5 py-8 text-center dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-10">
|
||||
🎨
|
||||
</view>
|
||||
<view class="mb-2 text-6 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
UnoCSS 原子化CSS
|
||||
</view>
|
||||
<view class="mb-2 text-3.5 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
即时按需的原子化CSS引擎
|
||||
</view>
|
||||
<view class="text-3 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
具有高性能且极具灵活性的即时原子化CSS引擎
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- UnoCSS 核心特性 -->
|
||||
<demo-block title="UnoCSS 核心特性" transparent>
|
||||
<view class="grid grid-cols-2 gap-3">
|
||||
<view
|
||||
v-for="feature in unocssFeatures"
|
||||
:key="feature.title"
|
||||
class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-2 text-6">
|
||||
{{ feature.icon }}
|
||||
</view>
|
||||
<view class="mb-1 text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ feature.title }}
|
||||
</view>
|
||||
<view class="mb-2 text-3 text-gray-600 leading-snug dark:text-[var(--wot-dark-color2)]">
|
||||
{{ feature.desc }}
|
||||
</view>
|
||||
<view class="rounded bg-gray-100 px-2 py-1 text-2.5 text-gray-700 font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]">
|
||||
{{ feature.example }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 颜色系统 -->
|
||||
<demo-block title="颜色系统" transparent>
|
||||
<view
|
||||
v-for="category in colorCategories"
|
||||
:key="category.name"
|
||||
class="mb-4 last:mb-0"
|
||||
>
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ category.name }}
|
||||
</view>
|
||||
<view class="grid grid-cols-3 gap-2">
|
||||
<view
|
||||
v-for="color in category.colors"
|
||||
:key="color.name"
|
||||
class="overflow-hidden rounded-2 bg-white shadow-sm dark:bg-[var(--wot-dark-background2)]"
|
||||
@click="copyCode(color.class)"
|
||||
>
|
||||
<view :class="color.class" class="h-12 w-full" />
|
||||
<view class="p-2">
|
||||
<view class="text-2.5 text-gray-800 font-mono dark:text-[var(--wot-dark-color)]">
|
||||
{{ color.name }}
|
||||
</view>
|
||||
<view class="text-2 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
{{ color.value }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 布局系统 -->
|
||||
<demo-block title="布局系统" transparent>
|
||||
<view class="space-y-4">
|
||||
<view
|
||||
v-for="example in layoutExamples"
|
||||
:key="example.title"
|
||||
class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]"
|
||||
>
|
||||
<view class="mb-3 flex items-center justify-between">
|
||||
<view class="text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
{{ example.title }}
|
||||
</view>
|
||||
<view class="rounded bg-gray-100 px-2 py-1 text-2.5 text-gray-700 font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]" @click="copyCode(example.code)">
|
||||
{{ example.code }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="example.title === 'Flex 居中'" :class="example.class">
|
||||
<text class="text-3.5">
|
||||
居中内容
|
||||
</text>
|
||||
</view>
|
||||
<view v-else-if="example.title === 'Grid 网格'" :class="example.class">
|
||||
<view
|
||||
v-for="n in 6"
|
||||
:key="n"
|
||||
class="rounded bg-blue-100 p-2 text-center text-3 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300"
|
||||
>
|
||||
{{ n }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-else :class="example.class">
|
||||
<text class="text-3.5">
|
||||
左侧
|
||||
</text>
|
||||
<text class="text-3.5">
|
||||
右侧
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 间距系统 -->
|
||||
<demo-block title="间距系统" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
内边距 (Padding)
|
||||
</view>
|
||||
<view class="mb-4 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
点击下方色块复制对应的 padding 类名
|
||||
</view>
|
||||
<view class="flex flex-wrap items-center gap-2">
|
||||
<view
|
||||
v-for="spacing in spacingExamples"
|
||||
:key="spacing.name"
|
||||
:class="spacing.class"
|
||||
class="cursor-pointer"
|
||||
@click="copyCode(spacing.name)"
|
||||
>
|
||||
<text class="text-2.5 text-gray-700 font-mono">
|
||||
{{ spacing.name }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-4 text-2.5 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
💡 提示:p-1 = 4px, p-2 = 8px, p-4 = 16px, p-6 = 24px, p-8 = 32px
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 字体系统 -->
|
||||
<demo-block title="字体系统" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
字体大小
|
||||
</view>
|
||||
<view class="space-y-3">
|
||||
<view
|
||||
v-for="font in fontExamples"
|
||||
:key="font.name"
|
||||
class="flex items-center justify-between border-b border-gray-100 pb-2 last:border-b-0 dark:border-[var(--wot-dark-border)]"
|
||||
@click="copyCode(font.name)"
|
||||
>
|
||||
<text :class="font.class" class="text-gray-800 dark:text-[var(--wot-dark-color)]">
|
||||
字体演示文字
|
||||
</text>
|
||||
<view class="flex items-center space-x-2">
|
||||
<text class="text-2.5 text-gray-500 dark:text-[var(--wot-dark-color2)]">
|
||||
{{ font.size }}
|
||||
</text>
|
||||
<text class="rounded bg-gray-100 px-2 py-1 text-2.5 text-gray-700 font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]">
|
||||
{{ font.name }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 阴影效果 -->
|
||||
<demo-block title="阴影效果" transparent>
|
||||
<view class="space-y-3">
|
||||
<view
|
||||
v-for="effect in effectExamples"
|
||||
:key="effect.name"
|
||||
:class="effect.class"
|
||||
@click="copyCode(effect.name)"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<text class="text-3.5 text-gray-800">
|
||||
阴影效果演示
|
||||
</text>
|
||||
<text class="rounded bg-gray-100 px-2 py-1 text-2.5 text-gray-700 font-mono">
|
||||
{{ effect.name }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 交互效果 -->
|
||||
<demo-block title="交互效果" transparent>
|
||||
<view class="space-y-4">
|
||||
<!-- 悬停效果 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
悬停效果
|
||||
</view>
|
||||
<view class="grid grid-cols-2 gap-3">
|
||||
<view class="rounded-2 bg-blue-100 p-4 text-center transition-all duration-300 active:scale-95 hover:scale-105 hover:bg-blue-200">
|
||||
<text class="text-3 text-blue-800">
|
||||
悬停变色
|
||||
</text>
|
||||
</view>
|
||||
<view class="rounded-2 bg-green-100 p-4 text-center transition-all duration-300 hover:shadow-lg hover:-translate-y-1">
|
||||
<text class="text-3 text-green-800">
|
||||
悬停上浮
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-3 rounded bg-gray-100 p-2 text-2.5 text-gray-700 font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]" @click="copyCode('hover:bg-blue-200 hover:scale-105 transition-all duration-300')">
|
||||
hover:bg-blue-200 hover:scale-105 transition-all duration-300
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 动画效果 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
动画效果
|
||||
</view>
|
||||
<wd-button type="primary" block @click="toggleAnimation">
|
||||
切换动画状态
|
||||
</wd-button>
|
||||
<view class="mt-4 flex justify-center">
|
||||
<view
|
||||
class="rounded-2 p-6 text-center transition-all duration-500 ease-in-out"
|
||||
:class="[
|
||||
animationState
|
||||
? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white transform rotate-12 scale-110 shadow-lg'
|
||||
: 'bg-gray-100 text-gray-800 transform rotate-0 scale-100 shadow-sm dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color)]',
|
||||
]"
|
||||
>
|
||||
<text class="text-4 font-bold">
|
||||
动画演示
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-3 rounded bg-gray-100 p-2 text-2.5 text-gray-700 leading-relaxed font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]" @click="copyCode('transition-all duration-500 ease-in-out transform rotate-12 scale-110')">
|
||||
transition-all duration-500 ease-in-out\n
|
||||
transform rotate-12 scale-110
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 响应式设计 -->
|
||||
<demo-block title="响应式设计" transparent>
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
响应式断点
|
||||
</view>
|
||||
<view class="mb-4 text-3 text-gray-600 leading-relaxed dark:text-[var(--wot-dark-color2)]">
|
||||
UnoCSS 支持响应式断点,可以根据屏幕尺寸应用不同样式
|
||||
</view>
|
||||
<view class="mb-4 rounded-2 bg-red-100 p-4 text-center dark:bg-red-900/30 lg:bg-yellow-100 md:bg-blue-100 sm:bg-green-100 dark:lg:bg-yellow-900/30 dark:md:bg-blue-900/30 dark:sm:bg-green-900/30">
|
||||
<text class="text-3.5 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
响应式背景色
|
||||
</text>
|
||||
</view>
|
||||
<view class="grid grid-cols-1 gap-3 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2">
|
||||
<view
|
||||
v-for="n in 8"
|
||||
:key="n"
|
||||
class="rounded bg-purple-100 p-3 text-center text-3 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300"
|
||||
>
|
||||
项目 {{ n }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-4 rounded bg-gray-100 p-2 text-2.5 text-gray-700 leading-relaxed font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]" @click="copyCode('grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4')">
|
||||
grid-cols-1 sm:grid-cols-2\n
|
||||
md:grid-cols-3 lg:grid-cols-4
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 实用工具类 -->
|
||||
<demo-block title="实用工具类" transparent>
|
||||
<view class="space-y-4">
|
||||
<!-- 显示隐藏 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
显示/隐藏
|
||||
</view>
|
||||
<view class="mb-3 flex flex-wrap gap-2">
|
||||
<view class="rounded bg-green-100 px-3 py-2 text-3 text-green-800">
|
||||
显示 (block)
|
||||
</view>
|
||||
<view class="rounded bg-blue-100 px-3 py-2 text-3 text-blue-800">
|
||||
内联 (inline)
|
||||
</view>
|
||||
<view class="rounded bg-purple-100 px-3 py-2 text-3 text-purple-800">
|
||||
弹性 (flex)
|
||||
</view>
|
||||
</view>
|
||||
<view class="rounded bg-gray-100 p-2 text-2.5 text-gray-700 font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]" @click="copyCode('block inline flex hidden')">
|
||||
block inline flex hidden
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 定位 -->
|
||||
<view class="rounded-2 bg-white p-4 dark:bg-[var(--wot-dark-background2)]">
|
||||
<view class="mb-3 text-4 text-gray-800 font-bold dark:text-[var(--wot-dark-color)]">
|
||||
定位系统
|
||||
</view>
|
||||
<view class="relative h-24 rounded-2 bg-gray-100 dark:bg-[var(--wot-dark-background3)]">
|
||||
<view class="absolute left-2 top-2 rounded bg-red-500 px-2 py-1 text-2.5 text-white">
|
||||
top-2 left-2
|
||||
</view>
|
||||
<view class="absolute right-2 top-2 rounded bg-blue-500 px-2 py-1 text-2.5 text-white">
|
||||
top-2 right-2
|
||||
</view>
|
||||
<view class="absolute bottom-2 left-2 rounded bg-green-500 px-2 py-1 text-2.5 text-white">
|
||||
bottom-2 left-2
|
||||
</view>
|
||||
<view class="absolute bottom-2 right-2 rounded bg-purple-500 px-2 py-1 text-2.5 text-white">
|
||||
bottom-2 right-2
|
||||
</view>
|
||||
</view>
|
||||
<view class="mt-3 rounded bg-gray-100 p-2 text-2.5 text-gray-700 font-mono dark:bg-[var(--wot-dark-background3)] dark:text-[var(--wot-dark-color2)]" @click="copyCode('absolute relative top-2 left-2 right-2 bottom-2')">
|
||||
absolute relative top-2 left-2 right-2 bottom-2
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
|
||||
<!-- 相关链接 -->
|
||||
<demo-block title="相关链接" transparent>
|
||||
<wd-cell-group border custom-class="rounded-2! overflow-hidden">
|
||||
<wd-cell title="📚 UnoCSS 官方文档" value="unocss.dev" is-link @click="handleNavigate('https://unocss.dev/')" />
|
||||
<wd-cell title="🐙 GitHub 仓库" value="unocss/unocss" is-link @click="handleNavigate('https://github.com/unocss/unocss')" />
|
||||
<wd-cell title="🎮 在线演练场" value="在线体验" is-link @click="handleNavigate('https://unocss.dev/play/')" />
|
||||
<wd-cell title="📖 Tailwind CSS" value="参考文档" is-link @click="handleNavigate('https://tailwindcss.com/docs')" />
|
||||
<wd-cell title="💡 最佳实践" value="使用指南" is-link @click="handleNavigate('https://unocss.dev/guide/')" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
name: 'root',
|
||||
style: {
|
||||
navigationBarTitleText: 'uni-ku/root',
|
||||
},
|
||||
})
|
||||
|
||||
const show = ref<boolean>(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<page-meta :page-style="`overflow:${show ? 'hidden' : 'visible'};`" />
|
||||
<view class="min-h-200vh">
|
||||
<demo-block title="锁定滚动" transparent>
|
||||
<wd-cell-group border>
|
||||
<wd-cell title="锁定滚动" is-link @click="show = !show" />
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
|
||||
<wd-popup
|
||||
v-model="show"
|
||||
lock-scroll
|
||||
position="bottom"
|
||||
closable
|
||||
:safe-area-inset-bottom="true"
|
||||
custom-style="height: 200px;"
|
||||
@close="show = false"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
Reference in New Issue
Block a user