完善页面
@@ -5,10 +5,7 @@
|
||||
>
|
||||
<view class="aside-header">
|
||||
<view class="logo">
|
||||
<text class="logo-text">{{ collapsed ? '商' : '商城后台' }}</text>
|
||||
</view>
|
||||
<view class="collapse-btn" @click="$emit('toggle')">
|
||||
<text class="collapse-text">{{ collapsed ? '›' : '‹' }}</text>
|
||||
<text class="logo-text"> 商城后台</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -38,7 +35,6 @@ defineProps<{
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(e:'toggle'): void
|
||||
(e:'menu-click', menuId: string): void
|
||||
}>()
|
||||
</script>
|
||||
@@ -58,12 +54,21 @@ defineEmits<{
|
||||
.aside-header{
|
||||
height: 56px;
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
align-items:center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||||
}
|
||||
.logo-text{ color:#fff; font-size:14px; font-weight:600; }
|
||||
.logo-text{
|
||||
color:#fff;
|
||||
font-size:20px;
|
||||
font-weight:600;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
align-items:center;
|
||||
text-align:center;
|
||||
}
|
||||
.collapse-btn{ width:28px; height:28px; display:flex; align-items:center; justify-content:center; }
|
||||
.collapse-text{ color:rgba(255,255,255,0.7); }
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<view
|
||||
class="sub-sider"
|
||||
v-if="groups && groups.length > 0"
|
||||
:style="{ left: props.asideWidth + 'px', width: props.siderWidth + 'px' }"
|
||||
>
|
||||
<view class="sub-header">
|
||||
@@ -14,14 +13,22 @@
|
||||
:key="groupKey(g)"
|
||||
class="group"
|
||||
>
|
||||
<view class="group-title" @click="toggleGroup(groupKey(g))">
|
||||
<!-- ✅ 改:点击标题时,如果该组没有 children 但有 path,则当成“叶子菜单”直接跳 -->
|
||||
<view class="group-title" @click="handleGroupTitleClick(g)">
|
||||
<text class="group-title-text">{{ g.title }}</text>
|
||||
<text class="group-arrow" :class="{ open: isGroupOpen(groupKey(g)) }">v</text>
|
||||
|
||||
<!-- ✅ 改:只有有 children 才显示箭头 -->
|
||||
<text
|
||||
v-if="groupChildren(g).length > 0"
|
||||
class="group-arrow"
|
||||
:class="{ open: isGroupOpen(groupKey(g)) }"
|
||||
>v</text>
|
||||
</view>
|
||||
|
||||
<!-- ✅ 改:v-show 的条件不变,但 children 的遍历必须兜底 -->
|
||||
<view v-show="isGroupOpen(groupKey(g))" class="group-children">
|
||||
<view
|
||||
v-for="c in g.children"
|
||||
v-for="c in groupChildren(g)"
|
||||
:key="c.id"
|
||||
class="sub-item"
|
||||
:class="{ active: resolvedActiveId === c.id }"
|
||||
@@ -38,16 +45,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed, watch, withDefaults } from 'vue'
|
||||
import type { MenuGroup, MenuChild } from '../types.uts'
|
||||
|
||||
const props = defineProps<{
|
||||
const props = withDefaults(defineProps<{
|
||||
activeMenuTitle: string
|
||||
groups: MenuGroup[]
|
||||
activeSubId: string
|
||||
activeMenuId?: string | null
|
||||
asideWidth: number
|
||||
siderWidth: number
|
||||
}>()
|
||||
}>(), {
|
||||
activeMenuId: 'home',
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'sub-click', child: MenuChild): void
|
||||
@@ -58,33 +68,60 @@ const openGroupKey = ref<string>('')
|
||||
|
||||
/** 给 group 一个稳定 key:优先用 id(如果你 types 里没有 id,就用 title) */
|
||||
const groupKey = (g: MenuGroup): string => {
|
||||
// @ts-ignore - 允许 g.id 可选
|
||||
// @ts-ignore
|
||||
const anyG: any = g as any
|
||||
return (anyG.id && (anyG.id as string)) ? (anyG.id as string) : g.title
|
||||
}
|
||||
|
||||
/** ✅ 核心:group.children 兜底成 [](因为 children 现在可选/可空) */
|
||||
const groupChildren = (g: MenuGroup): MenuChild[] => {
|
||||
// @ts-ignore
|
||||
const anyG: any = g as any
|
||||
// @ts-ignore
|
||||
const list = anyG.children as (MenuChild[] | null | undefined)
|
||||
return list && list.length > 0 ? list : []
|
||||
}
|
||||
|
||||
/** ✅ 兼容四级:child.children 兜底成 [] */
|
||||
const childChildren = (c: MenuChild): MenuChild[] => {
|
||||
// @ts-ignore
|
||||
const anyC: any = c as any
|
||||
// @ts-ignore
|
||||
const list = anyC.children as (MenuChild[] | null | undefined)
|
||||
return list && list.length > 0 ? list : []
|
||||
}
|
||||
|
||||
/** ✅ 叶子 group(无 children)如果有 path,则构造一个“伪 MenuChild”用于 emit 跳转 */
|
||||
const groupAsChild = (g: MenuGroup): MenuChild | null => {
|
||||
// @ts-ignore
|
||||
const anyG: any = g as any
|
||||
// @ts-ignore
|
||||
const p = anyG.path as (string | null | undefined)
|
||||
if (!p) return null
|
||||
return { id: groupKey(g), title: g.title, path: p } as MenuChild
|
||||
}
|
||||
|
||||
const normalizePath = (p: string): string => {
|
||||
if (!p) return ''
|
||||
// 统一去掉开头 /
|
||||
const s = p.startsWith('/') ? p.slice(1) : p
|
||||
// 去掉 query
|
||||
const q = s.indexOf('?')
|
||||
return q >= 0 ? s.slice(0, q) : s
|
||||
}
|
||||
|
||||
/** 扁平查找:id -> child */
|
||||
/** 扁平查找:id -> child(✅ 改:遍历时用 groupChildren/childChildren) */
|
||||
const findChildById = (id: string): MenuChild | null => {
|
||||
if (!id) return null
|
||||
|
||||
for (const g of props.groups) {
|
||||
for (const c of g.children) {
|
||||
// ✅ 叶子 group 也能命中
|
||||
const gLeaf = groupAsChild(g)
|
||||
if (gLeaf && gLeaf.id === id) return gLeaf
|
||||
|
||||
for (const c of groupChildren(g)) {
|
||||
if (c.id === id) return c
|
||||
// 兼容未来有更深层 children(递归)
|
||||
// @ts-ignore
|
||||
const anyC: any = c as any
|
||||
// @ts-ignore
|
||||
if (anyC.children && (anyC.children as MenuChild[]).length > 0) {
|
||||
// @ts-ignore
|
||||
const hit = findFirstMatchInChildren(id, anyC.children as MenuChild[])
|
||||
const deep = childChildren(c)
|
||||
if (deep.length > 0) {
|
||||
const hit = findFirstMatchInChildren(id, deep)
|
||||
if (hit) return hit
|
||||
}
|
||||
}
|
||||
@@ -92,16 +129,12 @@ const findChildById = (id: string): MenuChild | null => {
|
||||
return null
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const findFirstMatchInChildren = (id: string, list: MenuChild[]): MenuChild | null => {
|
||||
for (const n of list) {
|
||||
if (n.id === id) return n
|
||||
// @ts-ignore
|
||||
const anyN: any = n as any
|
||||
// @ts-ignore
|
||||
if (anyN.children && (anyN.children as MenuChild[]).length > 0) {
|
||||
// @ts-ignore
|
||||
const hit = findFirstMatchInChildren(id, anyN.children as MenuChild[])
|
||||
const deep = childChildren(n)
|
||||
if (deep.length > 0) {
|
||||
const hit = findFirstMatchInChildren(id, deep)
|
||||
if (hit) return hit
|
||||
}
|
||||
}
|
||||
@@ -111,16 +144,17 @@ const findFirstMatchInChildren = (id: string, list: MenuChild[]): MenuChild | nu
|
||||
const findChildByPath = (path: string): MenuChild | null => {
|
||||
const target = normalizePath(path)
|
||||
if (!target) return null
|
||||
|
||||
for (const g of props.groups) {
|
||||
for (const c of g.children) {
|
||||
// ✅ 叶子 group 也能按 path 命中
|
||||
const gLeaf = groupAsChild(g)
|
||||
if (gLeaf && normalizePath(gLeaf.path) === target) return gLeaf
|
||||
|
||||
for (const c of groupChildren(g)) {
|
||||
if (normalizePath(c.path) === target) return c
|
||||
// 兼容更深层 children(递归)
|
||||
// @ts-ignore
|
||||
const anyC: any = c as any
|
||||
// @ts-ignore
|
||||
if (anyC.children && (anyC.children as MenuChild[]).length > 0) {
|
||||
// @ts-ignore
|
||||
const hit = findFirstMatchByPath(target, anyC.children as MenuChild[])
|
||||
const deep = childChildren(c)
|
||||
if (deep.length > 0) {
|
||||
const hit = findFirstMatchByPath(target, deep)
|
||||
if (hit) return hit
|
||||
}
|
||||
}
|
||||
@@ -128,72 +162,62 @@ const findChildByPath = (path: string): MenuChild | null => {
|
||||
return null
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const findFirstMatchByPath = (targetNorm: string, list: MenuChild[]): MenuChild | null => {
|
||||
for (const n of list) {
|
||||
if (normalizePath(n.path) === targetNorm) return n
|
||||
// @ts-ignore
|
||||
const anyN: any = n as any
|
||||
// @ts-ignore
|
||||
if (anyN.children && (anyN.children as MenuChild[]).length > 0) {
|
||||
// @ts-ignore
|
||||
const hit = findFirstMatchByPath(targetNorm, anyN.children as MenuChild[])
|
||||
const deep = childChildren(n)
|
||||
if (deep.length > 0) {
|
||||
const hit = findFirstMatchByPath(targetNorm, deep)
|
||||
if (hit) return hit
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** 找到某个 child 属于哪个 group,用于自动展开该组 */
|
||||
/** 找到某个 child 属于哪个 group,用于自动展开该组(✅ 改:遍历兜底) */
|
||||
const findGroupKeyByChildId = (id: string): string => {
|
||||
for (const g of props.groups) {
|
||||
for (const c of g.children) {
|
||||
const gLeaf = groupAsChild(g)
|
||||
if (gLeaf && gLeaf.id === id) return groupKey(g)
|
||||
|
||||
for (const c of groupChildren(g)) {
|
||||
if (c.id === id) return groupKey(g)
|
||||
// @ts-ignore
|
||||
const anyC: any = c as any
|
||||
// @ts-ignore
|
||||
if (anyC.children && (anyC.children as MenuChild[]).length > 0) {
|
||||
// 深层命中也算这个 group
|
||||
// @ts-ignore
|
||||
const hit = findFirstMatchInChildren(id, anyC.children as MenuChild[])
|
||||
const deep = childChildren(c)
|
||||
if (deep.length > 0) {
|
||||
const hit = findFirstMatchInChildren(id, deep)
|
||||
if (hit) return groupKey(g)
|
||||
}
|
||||
}
|
||||
}
|
||||
// fallback:第一个 group
|
||||
return props.groups.length > 0 ? groupKey(props.groups[0]) : ''
|
||||
}
|
||||
|
||||
/** 递归取第一个 leaf 菜单:你要求的“默认打开第一个页面(递归)” */
|
||||
/** 递归取第一个 leaf 菜单(✅ 改:children 兜底) */
|
||||
const firstLeaf = (): MenuChild | null => {
|
||||
if (!props.groups || props.groups.length === 0) return null
|
||||
const g0 = props.groups[0]
|
||||
if (!g0.children || g0.children.length === 0) return null
|
||||
const g0Children = groupChildren(g0)
|
||||
|
||||
const c0: any = g0.children[0] as any
|
||||
if (c0.children && (c0.children as MenuChild[]).length > 0) {
|
||||
// @ts-ignore
|
||||
return findFirstLeafInChildren(c0.children as MenuChild[])
|
||||
// ✅ 如果第一个 group 是叶子(无 children 但有 path),也能返回
|
||||
if (g0Children.length === 0) {
|
||||
return groupAsChild(g0)
|
||||
}
|
||||
return g0.children[0]
|
||||
|
||||
const c0 = g0Children[0]
|
||||
const deep = childChildren(c0)
|
||||
if (deep.length > 0) return findFirstLeafInChildren(deep)
|
||||
return c0
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const findFirstLeafInChildren = (list: MenuChild[]): MenuChild | null => {
|
||||
if (!list || list.length === 0) return null
|
||||
const n: any = list[0] as any
|
||||
if (n.children && (n.children as MenuChild[]).length > 0) {
|
||||
// @ts-ignore
|
||||
return findFirstLeafInChildren(n.children as MenuChild[])
|
||||
}
|
||||
return list[0]
|
||||
const n = list[0]
|
||||
const deep = childChildren(n)
|
||||
if (deep.length > 0) return findFirstLeafInChildren(deep)
|
||||
return n
|
||||
}
|
||||
|
||||
/**
|
||||
* 高亮兜底:如果 activeSubId 没同步(你现在遇到的“点了不高亮”),
|
||||
* 就按当前页面 route/path 再匹配一次。
|
||||
* uni-app-x 的 getCurrentPages() 返回页面对象,page.route 可取当前路由。:contentReference[oaicite:3]{index=3}
|
||||
*/
|
||||
/** 高亮兜底:按 activeSubId -> route/path 再匹配一次 */
|
||||
const resolvedActiveId = computed((): string => {
|
||||
const byId = findChildById(props.activeSubId)
|
||||
if (byId) return byId.id
|
||||
@@ -215,7 +239,6 @@ const resolvedActiveId = computed((): string => {
|
||||
|
||||
const isGroupOpen = (key: string): boolean => {
|
||||
if (!openGroupKey.value) {
|
||||
// 初始默认展开第一个组
|
||||
return props.groups && props.groups.length > 0 ? groupKey(props.groups[0]) === key : false
|
||||
}
|
||||
return openGroupKey.value === key
|
||||
@@ -225,24 +248,37 @@ const toggleGroup = (key: string) => {
|
||||
openGroupKey.value = (openGroupKey.value === key) ? '' : key
|
||||
}
|
||||
|
||||
/** ✅ 新增:点 group 标题时的行为 */
|
||||
const handleGroupTitleClick = (g: MenuGroup) => {
|
||||
const list = groupChildren(g)
|
||||
// 有 children:正常展开/收起
|
||||
if (list.length > 0) {
|
||||
toggleGroup(groupKey(g))
|
||||
return
|
||||
}
|
||||
// 无 children:如果有 path,当成叶子菜单直接跳
|
||||
const leaf = groupAsChild(g)
|
||||
if (leaf) {
|
||||
openGroupKey.value = groupKey(g)
|
||||
emit('sub-click', leaf)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = (c: MenuChild) => {
|
||||
// 点击就让该组展开(用户体验更 CRMEB)
|
||||
openGroupKey.value = findGroupKeyByChildId(c.id)
|
||||
emit('sub-click', c)
|
||||
}
|
||||
|
||||
/** 自动:当 groups 变了/activeSubId 无效时,默认跳第一个 leaf(递归)并展开对应 group */
|
||||
/** 自动:groups 变更/activeSubId 无效时,默认跳第一个 leaf 并展开对应 group */
|
||||
const ensureDefault = () => {
|
||||
if (!props.groups || props.groups.length === 0) return
|
||||
|
||||
// activeSubId 有效:展开它所在组
|
||||
const hit = findChildById(props.activeSubId)
|
||||
if (hit) {
|
||||
openGroupKey.value = findGroupKeyByChildId(hit.id)
|
||||
return
|
||||
}
|
||||
|
||||
// activeSubId 无效/空:默认递归选第一个 leaf
|
||||
const first = firstLeaf()
|
||||
if (first) {
|
||||
openGroupKey.value = findGroupKeyByChildId(first.id)
|
||||
@@ -264,6 +300,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 原样保留你的样式 */
|
||||
.sub-sider{
|
||||
background:#ffffff;
|
||||
border-right: 1px solid #e5e7eb;
|
||||
@@ -278,20 +315,21 @@ watch(
|
||||
height: 56px;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
padding: 0 16px;
|
||||
border-bottom: 1px solid #eef2f7;
|
||||
}
|
||||
.sub-title{
|
||||
font-size:16px;
|
||||
font-weight:700;
|
||||
color:#111827;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
align-items:center;
|
||||
}
|
||||
|
||||
.sub-body{
|
||||
height: calc(100vh - 56px);
|
||||
}
|
||||
|
||||
/* CRMEB 风格:分组“块”更明显 */
|
||||
.group{ padding: 8px 0; }
|
||||
|
||||
.group-title{
|
||||
@@ -324,11 +362,10 @@ watch(
|
||||
padding: 0 12px 6px 12px;
|
||||
}
|
||||
|
||||
/* 子菜单:缩进 + 更小高度 */
|
||||
.sub-item{
|
||||
height: 34px;
|
||||
margin: 4px 0;
|
||||
padding: 0 14px 0 28px; /* 体现层级 */
|
||||
padding: 0 14px 0 28px;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
:activeMenuTitle="activeMenuTitle"
|
||||
:groups="activeGroups"
|
||||
:activeSubId="activeSubId"
|
||||
:activeMenuId="activeMenuId || 'home'"
|
||||
:asideWidth="ASIDE_W"
|
||||
:siderWidth="SUB_W"
|
||||
@sub-click="onSubClick"
|
||||
@@ -63,7 +64,7 @@ import AdminFooter from './components/AdminFooter.uvue'
|
||||
import { menuList as menuConst } from './utils/menu.uts'
|
||||
import { findActiveByCurrentPage, getCurrentRoutePath } from './utils/nav.uts'
|
||||
import { makeTabFromPath, upsertTab, removeTab } from './utils/tabs.uts'
|
||||
import type { MenuItem, TabItem } from './types.uts'
|
||||
import type { MenuItem, TabItem , MenuChild } from './types.uts'
|
||||
|
||||
// 你页面传进来的 currentPage:可能是顶级 id,也可能是子页面 id(user-list)
|
||||
const props = defineProps<{ currentPage: string }>()
|
||||
@@ -115,19 +116,24 @@ syncTabsByRoute()
|
||||
// computed
|
||||
const activeMenu = computed(() => menuList.value.find(m => m.id === activeMenuId.value))
|
||||
const activeMenuTitle = computed(() => activeMenu.value?.title || '商城后台')
|
||||
const activeGroups = computed(() => activeMenu.value?.groups || [])
|
||||
const activeGroups = computed(() => {
|
||||
const m = menuList.value.find(it => it.id === activeMenuId.value)
|
||||
return m?.groups ?? [] // ✅ 永远是数组
|
||||
})
|
||||
|
||||
|
||||
const breadcrumb = computed(() => {
|
||||
// “一级 / 二级”
|
||||
let subTitle = ''
|
||||
const groups = activeGroups.value
|
||||
for (const g of groups) {
|
||||
const hit = g.children.find(c => c.id === activeSubId.value)
|
||||
const cs = g.children ?? []
|
||||
const hit = cs.find(c => c.id === activeSubId.value)
|
||||
if (hit) { subTitle = hit.title; break }
|
||||
}
|
||||
return subTitle ? `${activeMenuTitle.value} / ${subTitle}` : `${activeMenuTitle.value}`
|
||||
})
|
||||
|
||||
|
||||
// handlers
|
||||
const toggleCollapse = () => {
|
||||
isCollapsed.value = !isCollapsed.value
|
||||
@@ -153,27 +159,54 @@ const firstLeafOfMenu = (m: MenuItem): MenuChild | null => {
|
||||
return g0.children[0]
|
||||
}
|
||||
|
||||
const go = (url: string) => {
|
||||
// 你明确要用 navigateTo:页面栈会增长(这是正常行为):contentReference[oaicite:4]{index=4}
|
||||
uni.navigateTo({ url })
|
||||
let navigating = false
|
||||
|
||||
const go = async (url?: string | null) => {
|
||||
if (!url || url.length === 0) return
|
||||
if (navigating) return
|
||||
navigating = true
|
||||
try {
|
||||
await uni.navigateTo({ url })
|
||||
} catch (e) {
|
||||
// 可选:忽略取消类报错,避免控制台刷屏
|
||||
} finally {
|
||||
setTimeout(() => { navigating = false }, 80)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const onMenuClick = (menuId: string) => {
|
||||
const m = menuList.value.find(x => x.id === menuId)
|
||||
if (!m) return
|
||||
|
||||
activeMenuId.value = m.id
|
||||
// 默认激活该菜单第一个子项
|
||||
const g0 = (m.groups && m.groups.length > 0) ? m.groups[0] : null
|
||||
const c0 = g0 && g0.children.length > 0 ? g0.children[0] : null
|
||||
activeSubId.value = c0 ? c0.id : ''
|
||||
go(m.path)
|
||||
|
||||
const leaf = firstLeafOfMenu(m)
|
||||
activeSubId.value = leaf ? leaf.id : ''
|
||||
|
||||
// ✅ 优先 leaf.path,其次才考虑 m.path
|
||||
go(leaf?.path ?? m.path ?? '')
|
||||
}
|
||||
|
||||
const firstLeafInChildren = (list?: MenuChild[] | null): MenuChild | null => {
|
||||
const arr = list ?? []
|
||||
if (arr.length === 0) return null
|
||||
const n = arr[0]
|
||||
const deep = n.children ?? []
|
||||
return deep.length > 0 ? firstLeafInChildren(deep) : n
|
||||
}
|
||||
|
||||
const onSubClick = (c: MenuChild) => {
|
||||
activeSubId.value = c.id
|
||||
if (c.path && c.path.length > 0) {
|
||||
go(c.path)
|
||||
} else {
|
||||
const leaf = firstLeafInChildren(c.children)
|
||||
go(leaf?.path ?? '')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const onTabClick = (tab: TabItem) => {
|
||||
activeTabId.value = tab.id
|
||||
go(tab.path)
|
||||
@@ -216,6 +249,6 @@ const onNotify = () => uni.showToast({ title: '通知', icon: 'none' })
|
||||
height: calc(100vh - 56px - 44px);
|
||||
}
|
||||
.content-inner{
|
||||
padding: 16px;
|
||||
padding:5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -14,15 +14,26 @@ export type TagItem = {
|
||||
export type MenuChild = {
|
||||
id: string
|
||||
title: string
|
||||
path: string
|
||||
|
||||
// ✅ 目录节点可以没有 path
|
||||
path?: string | null
|
||||
|
||||
// ✅ 允许四级
|
||||
children?: MenuChild[] | null
|
||||
}
|
||||
|
||||
export type MenuGroup = {
|
||||
id?:string
|
||||
id?: string | null
|
||||
title: string
|
||||
children: MenuChild[]
|
||||
|
||||
// ✅ 允许 group 自己也能当叶子直接跳转(可选)
|
||||
path?: string | null
|
||||
|
||||
// ✅ children 允许缺省/为空
|
||||
children?: MenuChild[] | null
|
||||
}
|
||||
|
||||
|
||||
export type MenuItem = {
|
||||
id: string
|
||||
title: string
|
||||
|
||||
@@ -6,7 +6,7 @@ export const menuList: MenuItem[] = [
|
||||
title: '首页',
|
||||
icon: '/static/homepage.svg',
|
||||
path: '/pages/mall/admin/homePage/index',
|
||||
groups: [],
|
||||
groups: []
|
||||
},
|
||||
{
|
||||
id: 'user',
|
||||
@@ -15,46 +15,217 @@ export const menuList: MenuItem[] = [
|
||||
path: '/pages/mall/admin/user-management',
|
||||
groups: [
|
||||
{
|
||||
id:'user-management',
|
||||
id: 'user-management',
|
||||
title: '用户管理',
|
||||
children: [
|
||||
{ id: 'user-list', title: '用户列表', path: '/pages/mall/admin/user-management' },
|
||||
{ id: 'user-add', title: '添加用户', path: '/pages/mall/admin/user-management?action=add' },
|
||||
{ id: 'user-statistics', title: '用户统计', path: '/pages/mall/admin/user-statistics' },
|
||||
],
|
||||
{
|
||||
id: 'user-statistics',
|
||||
title: '用户统计',
|
||||
path: '/pages/mall/admin/user-statistics'
|
||||
},
|
||||
],
|
||||
{
|
||||
id: 'user-list',
|
||||
title: '用户管理',
|
||||
path: '/pages/mall/admin/user-management'
|
||||
},
|
||||
{
|
||||
id: 'user-group',
|
||||
title: '用户分组',
|
||||
path: '/pages/mall/admin/user-management?action=group'
|
||||
},
|
||||
{
|
||||
id: 'user-tag',
|
||||
title: '用户标签',
|
||||
path: '/pages/mall/admin/user-management?action=tag'
|
||||
},
|
||||
{
|
||||
id: 'user-level',
|
||||
title: '用户等级',
|
||||
path: '/pages/mall/admin/user-management?action=level'
|
||||
},
|
||||
{
|
||||
id: 'user-config',
|
||||
title: '用户配置',
|
||||
path: '/pages/mall/admin/user-management?action=config'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'order',
|
||||
title: '订单',
|
||||
icon: '/static/order.svg',
|
||||
path: '/pages/mall/admin/order-management',
|
||||
path: '/pages/mall/admin/order-management?tab=list',
|
||||
groups: [
|
||||
{
|
||||
id:'order-management',
|
||||
id: 'order-management',
|
||||
title: '订单管理',
|
||||
children: [
|
||||
{ id: 'order-list', title: '订单列表', path: '/pages/mall/admin/order-management' },
|
||||
],
|
||||
{
|
||||
id: 'order-stats',
|
||||
title: '订单统计',
|
||||
path: '/pages/mall/admin/order-management?tab=stats'
|
||||
},
|
||||
],
|
||||
{
|
||||
id: 'order-list',
|
||||
title: '订单管理',
|
||||
path: '/pages/mall/admin/order-management?tab=list'
|
||||
},
|
||||
{
|
||||
id: 'order-aftersale',
|
||||
title: '售后订单',
|
||||
path: '/pages/mall/admin/order-management?tab=aftersale'
|
||||
},
|
||||
{
|
||||
id: 'order-cashier',
|
||||
title: '收银订单',
|
||||
path: '/pages/mall/admin/order-management?tab=cashier'
|
||||
},
|
||||
{
|
||||
id: 'order-verify',
|
||||
title: '核销记录',
|
||||
path: '/pages/mall/admin/order-management?tab=verify'
|
||||
},
|
||||
{
|
||||
id: 'order-config',
|
||||
title: '订单配置',
|
||||
path: '/pages/mall/admin/order-management?tab=config'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'product',
|
||||
title: '商品',
|
||||
icon: '/static/shopping.svg',
|
||||
icon: '/static/product.svg',
|
||||
path: '/pages/mall/admin/product-management',
|
||||
groups: [
|
||||
{
|
||||
id:'product-management',
|
||||
id: 'product-management',
|
||||
title: '商品管理',
|
||||
children: [
|
||||
{ id: 'product-list', title: '商品列表', path: '/pages/mall/admin/product-management' },
|
||||
{ id: 'product-add', title: '添加商品', path: '/pages/mall/admin/product-management?action=add' },
|
||||
],
|
||||
{
|
||||
id: 'product-list',
|
||||
title: '商品管理',
|
||||
path: '/pages/mall/admin/product-management'
|
||||
},
|
||||
],
|
||||
{
|
||||
id: 'product-statistics',
|
||||
title: '商品统计',
|
||||
path: '/pages/mall/admin/product-statistics'
|
||||
},
|
||||
{
|
||||
id: 'product-classification',
|
||||
title: '商品分类',
|
||||
path: '/pages/mall/admin/product-classification'
|
||||
},
|
||||
{
|
||||
id: 'product-specifications',
|
||||
title: '商品规格',
|
||||
path: '/pages/mall/admin/product-specifications'
|
||||
},
|
||||
{
|
||||
id: 'product-parameters',
|
||||
title: '商品参数',
|
||||
path: '/pages/mall/admin/product-parameters'
|
||||
},
|
||||
{
|
||||
id: 'product-labels',
|
||||
title: '商品标签',
|
||||
path: '/pages/mall/admin/product-labels'
|
||||
},
|
||||
{
|
||||
id: 'product-protection',
|
||||
title: '商品保障',
|
||||
path: '/pages/mall/admin/product-protection'
|
||||
},
|
||||
{
|
||||
id: 'product-reviews',
|
||||
title: '商品评论',
|
||||
path: '/pages/mall/admin/product-reviews'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'design',
|
||||
title: '设计',
|
||||
icon: '/static/design.svg',
|
||||
path: '/pages/mall/admin/design/index',
|
||||
groups: [
|
||||
{
|
||||
id: 'design-management',
|
||||
title: '设计',
|
||||
children: [
|
||||
{
|
||||
id: 'design-home',
|
||||
title: '页面装修',
|
||||
path: '/pages/mall/admin/design/index'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'content',
|
||||
title: '文章',
|
||||
icon: '/static/content.svg',
|
||||
path: '/pages/mall/admin/content/index',
|
||||
groups: [
|
||||
{
|
||||
id: 'content-management',
|
||||
title: '文章',
|
||||
children: [
|
||||
{
|
||||
id: 'content-list',
|
||||
title: '文章管理',
|
||||
path: '/pages/mall/admin/content/index'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'customer-service',
|
||||
title: '客服',
|
||||
icon: '/static/customerService.svg',
|
||||
path: '/pages/mall/admin/customer-service/index',
|
||||
groups: [
|
||||
{
|
||||
id: 'customer-service',
|
||||
title: '客服',
|
||||
children: [
|
||||
{
|
||||
id: 'cs-list',
|
||||
title: '客服列表',
|
||||
path: '/pages/mall/admin/customer-service/list'
|
||||
},
|
||||
{
|
||||
id: 'cs-script',
|
||||
title: '客服话术',
|
||||
path: '/pages/mall/admin/customer-service/script'
|
||||
},
|
||||
{
|
||||
id: 'cs-message',
|
||||
title: '用户留言',
|
||||
path: '/pages/mall/admin/customer-service/messages'
|
||||
},
|
||||
{
|
||||
id: 'cs-auto-reply',
|
||||
title: '自动回复',
|
||||
path: '/pages/mall/admin/customer-service/auto-reply'
|
||||
},
|
||||
{
|
||||
id: 'cs-config',
|
||||
title: '客服配置',
|
||||
path: '/pages/mall/admin/customer-service/config'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'marketing',
|
||||
@@ -63,29 +234,206 @@ export const menuList: MenuItem[] = [
|
||||
path: '/pages/mall/admin/marketing-management',
|
||||
groups: [
|
||||
{
|
||||
id:'coupon',
|
||||
id: 'coupon',
|
||||
title: '优惠券活动',
|
||||
children: [
|
||||
{ id: 'coupon-list', title: '优惠券列表', path: '/pages/mall/admin/marketing/coupon/list' },
|
||||
{ id: 'coupon-receive', title: '领取情况', path: '/pages/mall/admin/marketing/coupon/receive' },
|
||||
],
|
||||
{
|
||||
id: 'coupon-list',
|
||||
title: '优惠券列表',
|
||||
path: '/pages/mall/admin/marketing/coupon/list'
|
||||
},
|
||||
{
|
||||
id:'points',
|
||||
title: '积分',
|
||||
children: [
|
||||
{ id: 'points-management', title: '积分管理', path: '/pages/mall/admin/marketing/points/index' },
|
||||
],
|
||||
id: 'coupon-receive',
|
||||
title: '领取情况',
|
||||
path: '/pages/mall/admin/marketing/coupon/receive'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id:'signin',
|
||||
title: '签到',
|
||||
id: 'points',
|
||||
title: '积分管理',
|
||||
children: [
|
||||
{ id: 'rule', title: '签到规则', path: '/pages/mall/admin/marketing/signin/rule' },
|
||||
{ id: 'record', title: '记录', path: '/pages/mall/admin/marketing/signin/record' },
|
||||
],
|
||||
{
|
||||
id: 'points-stats',
|
||||
title: '积分统计',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=stats'
|
||||
},
|
||||
],
|
||||
{
|
||||
id: 'points-goods',
|
||||
title: '积分商品',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=goods'
|
||||
},
|
||||
{
|
||||
id: 'points-order',
|
||||
title: '积分订单',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=order'
|
||||
},
|
||||
{
|
||||
id: 'points-record',
|
||||
title: '积分记录',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=record'
|
||||
},
|
||||
{
|
||||
id: 'points-config',
|
||||
title: '积分配置',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'lottery',
|
||||
title: '抽奖管理',
|
||||
children: [
|
||||
{
|
||||
id: 'lottery-list',
|
||||
title: '抽奖列表',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=lottery-list'
|
||||
},
|
||||
{
|
||||
id: 'lottery-config',
|
||||
title: '抽奖配置',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=lottery-config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'groupbuy',
|
||||
title: '拼团管理',
|
||||
children: [
|
||||
{
|
||||
id: 'groupbuy-goods',
|
||||
title: '拼团商品',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=groupbuy-goods'
|
||||
},
|
||||
{
|
||||
id: 'groupbuy-list',
|
||||
title: '拼团列表',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=groupbuy-list'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'seckill',
|
||||
title: '秒杀管理',
|
||||
children: [
|
||||
{
|
||||
id: 'seckill-goods',
|
||||
title: '秒杀商品',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=seckill-goods'
|
||||
},
|
||||
{
|
||||
id: 'seckill-list',
|
||||
title: '秒杀列表',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=seckill-list'
|
||||
},
|
||||
{
|
||||
id: 'seckill-config',
|
||||
title: '秒杀配置',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=seckill-config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'member',
|
||||
title: '会员管理',
|
||||
children: [
|
||||
{
|
||||
id: 'member-type',
|
||||
title: '会员类型',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=member-type'
|
||||
},
|
||||
{
|
||||
id: 'member-rights',
|
||||
title: '会员权益',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=member-rights'
|
||||
},
|
||||
{
|
||||
id: 'member-card',
|
||||
title: '卡密会员',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=member-card'
|
||||
},
|
||||
{
|
||||
id: 'member-record',
|
||||
title: '会员记录',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=member-record'
|
||||
},
|
||||
{
|
||||
id: 'member-config',
|
||||
title: '会员配置',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=member-config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'live',
|
||||
title: '直播管理',
|
||||
children: [
|
||||
{
|
||||
id: 'live-room',
|
||||
title: '直播间管理',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=live-room'
|
||||
},
|
||||
{
|
||||
id: 'live-goods',
|
||||
title: '直播商品管理',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=live-goods'
|
||||
},
|
||||
{
|
||||
id: 'live-anchor',
|
||||
title: '主播管理',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=live-anchor'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'recharge',
|
||||
title: '用户充值',
|
||||
children: [
|
||||
{
|
||||
id: 'recharge-amount',
|
||||
title: '金额设置',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=recharge-amount'
|
||||
},
|
||||
{
|
||||
id: 'recharge-config',
|
||||
title: '充值配置',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=recharge-config'
|
||||
},
|
||||
{
|
||||
id: 'recharge-record',
|
||||
title: '充值记录',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=recharge-record'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'signin',
|
||||
title: '每日签到',
|
||||
children: [
|
||||
{
|
||||
id: 'signin-rule',
|
||||
title: '签到配置',
|
||||
path: '/pages/mall/admin/marketing/signin/rule'
|
||||
},
|
||||
{
|
||||
id: 'signin-record',
|
||||
title: '签到奖励',
|
||||
path: '/pages/mall/admin/marketing/signin/record'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'newcomer',
|
||||
title: '新人礼',
|
||||
children: [
|
||||
{
|
||||
id: 'newcomer',
|
||||
title: '新人礼',
|
||||
path: '/pages/mall/admin/marketing/points/index?tab=newcomer'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'system',
|
||||
@@ -94,17 +442,296 @@ export const menuList: MenuItem[] = [
|
||||
path: '/pages/mall/admin/system-settings',
|
||||
groups: [
|
||||
{
|
||||
id:'system-settings',
|
||||
id: 'sys-basic',
|
||||
title: '系统设置',
|
||||
path: '/pages/mall/admin/system-settings',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'sys-message',
|
||||
title: '消息管理',
|
||||
path: '/pages/mall/admin/system/message-management',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'sys-agreement',
|
||||
title: '协议设置',
|
||||
path: '/pages/mall/admin/system/agreement-settings',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'sys-receipt',
|
||||
title: '小票配置',
|
||||
path: '/pages/mall/admin/system/receipt-settings',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'sys-permission',
|
||||
title: '管理权限',
|
||||
children: [
|
||||
{ id: 'basic', title: '基本设置', path: '/pages/mall/admin/system-settings' },
|
||||
{ id: 'security', title: '安全设置', path: '/pages/mall/admin/system-settings?tab=security' },
|
||||
{ id: 'email', title: '邮件设置', path: '/pages/mall/admin/system-settings?tab=security' },
|
||||
{ id: 'payment', title: '支付设置', path: '/pages/mall/admin/system-settings?tab=security' },
|
||||
{ id: 'other', title: '其他设置', path: '/pages/mall/admin/system-settings?tab=security' },
|
||||
|
||||
],
|
||||
{
|
||||
id: 'sys-role',
|
||||
title: '角色管理',
|
||||
path: '/pages/mall/admin/system/permission/role'
|
||||
},
|
||||
],
|
||||
{
|
||||
id: 'sys-admin',
|
||||
title: '管理员列表',
|
||||
path: '/pages/mall/admin/system/permission/admin-list'
|
||||
},
|
||||
{
|
||||
id: 'sys-perm-setting',
|
||||
title: '权限设置',
|
||||
path: '/pages/mall/admin/system/permission/permission-setting'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'sys-shipping',
|
||||
title: '发货设置',
|
||||
children: [
|
||||
{
|
||||
id: 'ship-courier',
|
||||
title: '配送员管理',
|
||||
path: '/pages/mall/admin/system/shipping/courier'
|
||||
},
|
||||
{
|
||||
id: 'ship-pickup',
|
||||
title: '提货点设置',
|
||||
path: '/pages/mall/admin/system/shipping/pickup/points',
|
||||
children: [
|
||||
{
|
||||
id: 'pickup-points',
|
||||
title: '提货点',
|
||||
path: '/pages/mall/admin/system/shipping/pickup/points'
|
||||
},
|
||||
{
|
||||
id: 'pickup-verifier',
|
||||
title: '核销员',
|
||||
path: '/pages/mall/admin/system/shipping/pickup/verifiers'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'ship-freight',
|
||||
title: '运费模板',
|
||||
path: '/pages/mall/admin/system/shipping/freight-template'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'sys-api',
|
||||
title: '接口配置',
|
||||
children: [
|
||||
{
|
||||
id: 'api-yht',
|
||||
title: '一号通',
|
||||
path: '/pages/mall/admin/system/api/yht/page',
|
||||
children: [
|
||||
{
|
||||
id: 'api-yht-page',
|
||||
title: '一号通页面',
|
||||
path: '/pages/mall/admin/system/api/yht/page'
|
||||
},
|
||||
{
|
||||
id: 'api-yht-config',
|
||||
title: '一号通配置',
|
||||
path: '/pages/mall/admin/system/api/yht/config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'api-storage',
|
||||
title: '系统存储配置',
|
||||
path: '/pages/mall/admin/system/api/storage'
|
||||
},
|
||||
{
|
||||
id: 'api-collect',
|
||||
title: '商品采集配置',
|
||||
path: '/pages/mall/admin/system/api/collect'
|
||||
},
|
||||
{
|
||||
id: 'api-logistics',
|
||||
title: '物流查询配置',
|
||||
path: '/pages/mall/admin/system/api/logistics'
|
||||
},
|
||||
{
|
||||
id: 'api-waybill',
|
||||
title: '电子面单配置',
|
||||
path: '/pages/mall/admin/system/api/waybill'
|
||||
},
|
||||
{
|
||||
id: 'api-sms',
|
||||
title: '短信接口配置',
|
||||
path: '/pages/mall/admin/system/api/sms'
|
||||
},
|
||||
{
|
||||
id: 'api-pay',
|
||||
title: '商城支付配置',
|
||||
path: '/pages/mall/admin/system/api/pay'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'maintain',
|
||||
title: '维护',
|
||||
icon: '/static/maintain.svg',
|
||||
path: '/pages/mall/admin/maintain/dev-config/category',
|
||||
groups: [
|
||||
{
|
||||
id: 'dev-config',
|
||||
title: '开发配置',
|
||||
children: [
|
||||
{
|
||||
id: 'dev-config-category',
|
||||
title: '配置分类',
|
||||
path: '/pages/mall/admin/maintain/dev-config/category'
|
||||
},
|
||||
{
|
||||
id: 'dev-config-combo',
|
||||
title: '组合数据',
|
||||
path: '/pages/mall/admin/maintain/dev-config/combination-data'
|
||||
},
|
||||
{
|
||||
id: 'dev-config-cron',
|
||||
title: '定时任务',
|
||||
path: '/pages/mall/admin/maintain/dev-config/cron-job'
|
||||
},
|
||||
{
|
||||
id: 'dev-config-permission',
|
||||
title: '权限维护',
|
||||
path: '/pages/mall/admin/maintain/dev-config/permission'
|
||||
},
|
||||
{
|
||||
id: 'dev-config-module',
|
||||
title: '模块配置',
|
||||
path: '/pages/mall/admin/maintain/dev-config/module-config'
|
||||
},
|
||||
{
|
||||
id: 'dev-config-event',
|
||||
title: '自定事件',
|
||||
path: '/pages/mall/admin/maintain/dev-config/custom-event'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'security-maintain',
|
||||
title: '安全维护',
|
||||
children: [
|
||||
{
|
||||
id: 'security-refresh-cache',
|
||||
title: '刷新缓存',
|
||||
path: '/pages/mall/admin/maintain/security/refresh-cache'
|
||||
},
|
||||
{
|
||||
id: 'security-system-log',
|
||||
title: '系统日志',
|
||||
path: '/pages/mall/admin/maintain/security/system-log'
|
||||
},
|
||||
{
|
||||
id: 'security-online-upgrade',
|
||||
title: '在线升级',
|
||||
path: '/pages/mall/admin/maintain/security/online-upgrade'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'data-maintain',
|
||||
title: '数据维护',
|
||||
children: [
|
||||
{
|
||||
id: 'data-logistics-company',
|
||||
title: '物流公司',
|
||||
path: '/pages/mall/admin/maintain/data/logistics-company'
|
||||
},
|
||||
{
|
||||
id: 'data-city-data',
|
||||
title: '城市数据',
|
||||
path: '/pages/mall/admin/maintain/data/city-data'
|
||||
},
|
||||
{
|
||||
id: 'data-clear-data',
|
||||
title: '清除数据',
|
||||
path: '/pages/mall/admin/maintain/data/clear-data'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'external-api',
|
||||
title: '对外接口',
|
||||
children: [
|
||||
{
|
||||
id: 'external-account',
|
||||
title: '账号管理',
|
||||
path: '/pages/mall/admin/maintain/external/account'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'i18n-setting',
|
||||
title: '语言设置',
|
||||
children: [
|
||||
{
|
||||
id: 'i18n-language-list',
|
||||
title: '语言列表',
|
||||
path: '/pages/mall/admin/maintain/i18n/language-list'
|
||||
},
|
||||
{
|
||||
id: 'i18n-language-detail',
|
||||
title: '语言详情',
|
||||
path: '/pages/mall/admin/maintain/i18n/language-detail'
|
||||
},
|
||||
{
|
||||
id: 'i18n-region-list',
|
||||
title: '地区列表',
|
||||
path: '/pages/mall/admin/maintain/i18n/region-list'
|
||||
},
|
||||
{
|
||||
id: 'i18n-translate-config',
|
||||
title: '翻译配置',
|
||||
path: '/pages/mall/admin/maintain/i18n/translate-config'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'dev-tools',
|
||||
title: '开发工具',
|
||||
children: [
|
||||
{
|
||||
id: 'dev-tools-db',
|
||||
title: '数据库管理',
|
||||
path: '/pages/mall/admin/maintain/dev-tools/database'
|
||||
},
|
||||
{
|
||||
id: 'dev-tools-file',
|
||||
title: '文件管理',
|
||||
path: '/pages/mall/admin/maintain/dev-tools/file'
|
||||
},
|
||||
{
|
||||
id: 'dev-tools-api',
|
||||
title: '接口管理',
|
||||
path: '/pages/mall/admin/maintain/dev-tools/api'
|
||||
},
|
||||
{
|
||||
id: 'dev-tools-codegen',
|
||||
title: '代码生成',
|
||||
path: '/pages/mall/admin/maintain/dev-tools/codegen'
|
||||
},
|
||||
{
|
||||
id: 'dev-tools-dict',
|
||||
title: '数据字典',
|
||||
path: '/pages/mall/admin/maintain/dev-tools/data-dict'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'system-info',
|
||||
title: '系统信息',
|
||||
path: '/pages/mall/admin/maintain/system-info',
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,24 +1,85 @@
|
||||
import type { MenuItem } from '../types.uts'
|
||||
// utils/nav.uts
|
||||
import type { MenuItem, MenuGroup, MenuChild } from '../types.uts'
|
||||
|
||||
export function findActiveByCurrentPage(
|
||||
menuList: MenuItem[],
|
||||
currentPage: string
|
||||
): { activeMenuId: string, activeSubId: string } {
|
||||
|
||||
const page = currentPage || ''
|
||||
|
||||
// 1) currentPage 直接是一级 menu id
|
||||
const mById = menuList.find(m => m.id === page)
|
||||
if (mById) {
|
||||
const leaf = firstLeafOfMenu(mById)
|
||||
return { activeMenuId: mById.id, activeSubId: leaf?.id ?? '' }
|
||||
}
|
||||
|
||||
// 2) currentPage 是 path(/pages/xxx 或 pages/xxx)
|
||||
const pageNorm = normalize(page)
|
||||
|
||||
export function findActiveByCurrentPage(menuList: MenuItem[], currentPage: string) {
|
||||
// currentPage 既可能是顶级菜单 id,也可能是子页面 id(如 user-list)
|
||||
// 返回:activeMenuId / activeSubId / activeGroupTitle
|
||||
for (const m of menuList) {
|
||||
if (m.id === currentPage) {
|
||||
return { activeMenuId: m.id, activeSubId: '', activeGroupTitle: '' }
|
||||
}
|
||||
const groups = m.groups || []
|
||||
const groups = m.groups ?? []
|
||||
|
||||
// group / child / 四级 全部扫描
|
||||
for (const g of groups) {
|
||||
for (const c of g.children) {
|
||||
if (c.id === currentPage) {
|
||||
return { activeMenuId: m.id, activeSubId: c.id, activeGroupTitle: g.title }
|
||||
// group 叶子(可选)
|
||||
if (g.path && normalize(g.path) === pageNorm) {
|
||||
return { activeMenuId: m.id, activeSubId: '' }
|
||||
}
|
||||
|
||||
const cs = g.children ?? []
|
||||
for (const c of cs) {
|
||||
// 用 id 命中
|
||||
if (c.id === page) return { activeMenuId: m.id, activeSubId: c.id }
|
||||
// 用 path 命中
|
||||
if (c.path && normalize(c.path) === pageNorm) return { activeMenuId: m.id, activeSubId: c.id }
|
||||
|
||||
// 四级
|
||||
const ds = c.children ?? []
|
||||
const hit = findInChildren(ds, page, pageNorm)
|
||||
if (hit) return { activeMenuId: m.id, activeSubId: hit.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return { activeMenuId: menuList[0]?.id || 'home', activeSubId: '', activeGroupTitle: '' }
|
||||
|
||||
// 3) 找不到:兜底 home
|
||||
return { activeMenuId: 'home', activeSubId: '' }
|
||||
}
|
||||
|
||||
function findInChildren(list: MenuChild[], targetId: string, targetPathNorm: string): MenuChild | null {
|
||||
for (const n of list) {
|
||||
if (n.id === targetId) return n
|
||||
if (n.path && normalize(n.path) === targetPathNorm) return n
|
||||
const deep = n.children ?? []
|
||||
if (deep.length > 0) {
|
||||
const hit = findInChildren(deep, targetId, targetPathNorm)
|
||||
if (hit) return hit
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function normalize(p: string): string {
|
||||
if (!p) return ''
|
||||
const s = p.startsWith('/') ? p.slice(1) : p
|
||||
const q = s.indexOf('?')
|
||||
return q >= 0 ? s.slice(0, q) : s
|
||||
}
|
||||
|
||||
// 你可以把 index.uvue 里的 firstLeafOfMenu 移到这里复用(保持逻辑一致)
|
||||
function firstLeafOfMenu(m: MenuItem): MenuChild | null {
|
||||
const gs = m.groups ?? []
|
||||
if (gs.length === 0) return null
|
||||
const g0 = gs[0]
|
||||
const cs = g0.children ?? []
|
||||
if (cs.length === 0) return null
|
||||
let n = cs[0]
|
||||
while (n.children && n.children.length > 0) n = n.children[0]
|
||||
return n
|
||||
}
|
||||
|
||||
|
||||
export function getCurrentRoutePath(): string {
|
||||
// 使用页面栈获取当前路由(uni-app标准能力)
|
||||
// getCurrentPages 用于获取当前页面栈实例 :contentReference[oaicite:2]{index=2}
|
||||
|
||||
371
pages.json
@@ -431,119 +431,190 @@
|
||||
"root": "pages/mall/admin",
|
||||
"pages": [
|
||||
{
|
||||
"path": "user-management",
|
||||
"path": "content/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户管理",
|
||||
"navigationBarTitleText": "文章管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"path": "design/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "页面装修",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-management",
|
||||
"path": "maintain/data/city-data",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品管理",
|
||||
"navigationBarTitleText": "城市数据",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "order-management",
|
||||
"path": "maintain/data/clear-data",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单管理",
|
||||
"navigationBarTitleText": "清除数据",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "finance-management",
|
||||
"path": "maintain/data/logistics-company",
|
||||
"style": {
|
||||
"navigationBarTitleText": "财务管理",
|
||||
"navigationBarTitleText": "物流公司",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "user-statistics",
|
||||
"path": "maintain/dev-config/category",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户统计",
|
||||
"navigationBarTitleText": "配置分类",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system-settings",
|
||||
"path": "maintain/dev-config/combination-data",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统设置",
|
||||
"navigationBarTitleText": "组合数据",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "profile",
|
||||
"path": "maintain/dev-config/cron-job",
|
||||
"style": {
|
||||
"navigationBarTitleText": "管理后台"
|
||||
"navigationBarTitleText": "定时任务",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "delivery-management",
|
||||
"path": "maintain/dev-config/custom-event",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配送管理"
|
||||
"navigationBarTitleText": "自定事件",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "merchant-management",
|
||||
"path": "maintain/dev-config/module-config",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商家管理"
|
||||
"navigationBarTitleText": "模块配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "merchant-review",
|
||||
"path": "maintain/dev-config/permission",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商家审核"
|
||||
"navigationBarTitleText": "权限维护",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-review",
|
||||
"path": "maintain/dev-tools/api",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品审核"
|
||||
"navigationBarTitleText": "接口管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "refund-review",
|
||||
"path": "maintain/dev-tools/codegen",
|
||||
"style": {
|
||||
"navigationBarTitleText": "退款审核"
|
||||
"navigationBarTitleText": "代码生成",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "complaints",
|
||||
"path": "maintain/dev-tools/data-dict",
|
||||
"style": {
|
||||
"navigationBarTitleText": "投诉处理"
|
||||
"navigationBarTitleText": "数据字典",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "notifications",
|
||||
"path": "maintain/dev-tools/database",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通知"
|
||||
"navigationBarTitleText": "数据库管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "activity-log",
|
||||
"path": "maintain/dev-tools/file",
|
||||
"style": {
|
||||
"navigationBarTitleText": "活动日志"
|
||||
"navigationBarTitleText": "文件管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "subscription/plan-management",
|
||||
"path": "maintain/external/account",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订阅方案管理"
|
||||
"navigationBarTitleText": "账号管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "subscription/user-subscriptions",
|
||||
"path": "maintain/i18n/language-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户订阅管理"
|
||||
"navigationBarTitleText": "语言详情",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "marketing/coupon/coupon-management",
|
||||
"path": "maintain/i18n/language-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "优惠券管理"
|
||||
"navigationBarTitleText": "语言列表",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "maintain/i18n/region-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "地区列表",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "maintain/i18n/translate-config",
|
||||
"style": {
|
||||
"navigationBarTitleText": "翻译配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "maintain/security/online-upgrade",
|
||||
"style": {
|
||||
"navigationBarTitleText": "在线升级",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "maintain/security/refresh-cache",
|
||||
"style": {
|
||||
"navigationBarTitleText": "刷新缓存",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "maintain/security/system-log",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统日志",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "maintain/system-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统信息",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "marketing-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "营销管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "marketing/coupon/list",
|
||||
"style": {
|
||||
@@ -562,16 +633,240 @@
|
||||
"navigationBarTitleText": "积分管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "marketing/signin/record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "签到记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "marketing/signin/rule",
|
||||
"style": {
|
||||
"navigationBarTitleText": "签到规则"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"path": "marketing/signin/record",
|
||||
"path": "order-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "签到记录"
|
||||
"navigationBarTitleText": "订单管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-classification",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品分类",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-labels",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品标签",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-parameters",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品参数",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-protection",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品保障",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-reviews",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品审核"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-specifications",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品规格",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-statistics",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品统计",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "subscription/plan-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订阅方案管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "subscription/user-subscriptions",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户订阅管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system-settings",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统设置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/agreement-settings",
|
||||
"style": {
|
||||
"navigationBarTitleText": "协议设置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/collect",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品采集配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/logistics",
|
||||
"style": {
|
||||
"navigationBarTitleText": "物流查询配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/pay",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商城支付配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/sms",
|
||||
"style": {
|
||||
"navigationBarTitleText": "短信接口配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/storage",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统存储配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/waybill",
|
||||
"style": {
|
||||
"navigationBarTitleText": "电子面单配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/yht/config",
|
||||
"style": {
|
||||
"navigationBarTitleText": "一号通配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/api/yht/page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "一号通页面",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/message-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/permission/admin-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "管理员列表",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/permission/permission-setting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "权限设置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/permission/role",
|
||||
"style": {
|
||||
"navigationBarTitleText": "角色管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/receipt-settings",
|
||||
"style": {
|
||||
"navigationBarTitleText": "小票配置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/shipping/courier",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配送员管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/shipping/freight-template",
|
||||
"style": {
|
||||
"navigationBarTitleText": "运费模板",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/shipping/pickup/points",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提货点",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "system/shipping/pickup/verifiers",
|
||||
"style": {
|
||||
"navigationBarTitleText": "核销员",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "user-management",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户管理",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "user-statistics",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户统计",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<view class="activity-log">
|
||||
<view class="page-header">
|
||||
<text class="page-title">活动日志</text>
|
||||
<text class="page-subtitle">查看系统活动和操作日志</text>
|
||||
</view>
|
||||
|
||||
<view class="log-content">
|
||||
<text class="coming-soon">活动日志功能正在开发中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// 统一的导航方法
|
||||
const go = (url: string) => {
|
||||
// 1) 目标页面必须是非 tabBar 页面
|
||||
// 2) 必须在 pages.json / subPackages 注册
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.activity-log {
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #212529;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
|
||||
.log-content {
|
||||
background-color: #fff;
|
||||
padding: 60rpx 40rpx;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.coming-soon {
|
||||
font-size: 28rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<view class="complaints">
|
||||
<view class="page-header">
|
||||
<text class="page-title">投诉处理</text>
|
||||
<text class="page-subtitle">处理用户投诉和反馈</text>
|
||||
</view>
|
||||
|
||||
<view class="complaints-content">
|
||||
<text class="coming-soon">投诉处理功能正在开发中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// 统一的导航方法
|
||||
const go = (url: string) => {
|
||||
// 1) 目标页面必须是非 tabBar 页面
|
||||
// 2) 必须在 pages.json / subPackages 注册
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.complaints {
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #212529;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
|
||||
.complaints-content {
|
||||
background-color: #fff;
|
||||
padding: 60rpx 40rpx;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.coming-soon {
|
||||
font-size: 28rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/content/index.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">文章管理</text>
|
||||
<text class="SubTitle">content/index</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
95
pages/mall/admin/customer-service/auto-reply.uvue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="topbar">
|
||||
<view class="topbar-left">
|
||||
<text class="title">自动回复</text>
|
||||
<text class="subtitle">customer-service/auto-reply</text>
|
||||
</view>
|
||||
<view class="topbar-right">
|
||||
<view class="btn" @click="onBack"><text class="btn-text">返回</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h1">自动回复</text>
|
||||
<text class="p">这是页面骨架(可跑)。你可以在这里接入你们项目的 TopBar / Container 组件与业务逻辑。</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const onBack = () => {
|
||||
// H5/小程序均可用
|
||||
uni.navigateBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f6;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
.subtitle {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.topbar-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.topbar-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #111827;
|
||||
}
|
||||
.btn-text {
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
.card {
|
||||
padding: 16px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #eef0f6;
|
||||
}
|
||||
.h1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.p {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
95
pages/mall/admin/customer-service/config.uvue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="topbar">
|
||||
<view class="topbar-left">
|
||||
<text class="title">客服设置</text>
|
||||
<text class="subtitle">customer-service/config</text>
|
||||
</view>
|
||||
<view class="topbar-right">
|
||||
<view class="btn" @click="onBack"><text class="btn-text">返回</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h1">客服设置</text>
|
||||
<text class="p">这是页面骨架(可跑)。你可以在这里接入你们项目的 TopBar / Container 组件与业务逻辑。</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const onBack = () => {
|
||||
// H5/小程序均可用
|
||||
uni.navigateBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f6;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
.subtitle {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.topbar-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.topbar-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #111827;
|
||||
}
|
||||
.btn-text {
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
.card {
|
||||
padding: 16px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #eef0f6;
|
||||
}
|
||||
.h1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.p {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
95
pages/mall/admin/customer-service/list.uvue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="topbar">
|
||||
<view class="topbar-left">
|
||||
<text class="title">客服列表</text>
|
||||
<text class="subtitle">customer-service/list</text>
|
||||
</view>
|
||||
<view class="topbar-right">
|
||||
<view class="btn" @click="onBack"><text class="btn-text">返回</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h1">客服列表</text>
|
||||
<text class="p">这是页面骨架(可跑)。你可以在这里接入你们项目的 TopBar / Container 组件与业务逻辑。</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const onBack = () => {
|
||||
// H5/小程序均可用
|
||||
uni.navigateBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f6;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
.subtitle {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.topbar-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.topbar-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #111827;
|
||||
}
|
||||
.btn-text {
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
.card {
|
||||
padding: 16px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #eef0f6;
|
||||
}
|
||||
.h1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.p {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
95
pages/mall/admin/customer-service/messages.uvue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="topbar">
|
||||
<view class="topbar-left">
|
||||
<text class="title">客服消息</text>
|
||||
<text class="subtitle">customer-service/messages</text>
|
||||
</view>
|
||||
<view class="topbar-right">
|
||||
<view class="btn" @click="onBack"><text class="btn-text">返回</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h1">客服消息</text>
|
||||
<text class="p">这是页面骨架(可跑)。你可以在这里接入你们项目的 TopBar / Container 组件与业务逻辑。</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const onBack = () => {
|
||||
// H5/小程序均可用
|
||||
uni.navigateBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f6;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
.subtitle {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.topbar-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.topbar-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #111827;
|
||||
}
|
||||
.btn-text {
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
.card {
|
||||
padding: 16px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #eef0f6;
|
||||
}
|
||||
.h1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.p {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
95
pages/mall/admin/customer-service/script.uvue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="topbar">
|
||||
<view class="topbar-left">
|
||||
<text class="title">快捷回复话术</text>
|
||||
<text class="subtitle">customer-service/script</text>
|
||||
</view>
|
||||
<view class="topbar-right">
|
||||
<view class="btn" @click="onBack"><text class="btn-text">返回</text></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h1">快捷回复话术</text>
|
||||
<text class="p">这是页面骨架(可跑)。你可以在这里接入你们项目的 TopBar / Container 组件与业务逻辑。</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const onBack = () => {
|
||||
// H5/小程序均可用
|
||||
uni.navigateBack()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #f6f7fb;
|
||||
}
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 16px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #eef0f6;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
.subtitle {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.topbar-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.topbar-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.btn {
|
||||
padding: 8px 10px;
|
||||
border-radius: 10px;
|
||||
background: #111827;
|
||||
}
|
||||
.btn-text {
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
.card {
|
||||
padding: 16px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #eef0f6;
|
||||
}
|
||||
.h1 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.p {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<text>配送管理 - 占位页</text>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="uts">
|
||||
export default {}
|
||||
</script>
|
||||
<style>
|
||||
.page { padding: 30rpx; }
|
||||
</style>
|
||||
62
pages/mall/admin/design/index.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">页面装修</text>
|
||||
<text class="SubTitle">design/index</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
13
pages/mall/admin/maintain/data/city-data.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">城市数据</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 城市数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/data/clear-data.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">清除数据</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 清除数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/data/logistics-company.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">物流公司</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 物流公司</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-config/category.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">配置分类</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 配置分类</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-config/combination-data.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">组合数据</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 组合数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-config/cron-job.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">定时任务</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 定时任务</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-config/custom-event.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">自定事件</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 自定事件</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-config/module-config.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">模块配置</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 模块配置</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-config/permission.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">权限维护</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 权限维护</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-tools/api.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">接口管理</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 接口管理</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-tools/codegen.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">代码生成</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 代码生成</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-tools/data-dict.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">数据字典</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 数据字典</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-tools/database.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">数据库管理</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 数据库管理</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/dev-tools/file.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">文件管理</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 文件管理</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/external/account.uvue
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">账号管理</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 账号管理</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/i18n/language-detail.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">语言详情</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 语言详情</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/i18n/language-list.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">语言列表</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 语言列表</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/i18n/region-list.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">地区列表</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 地区列表</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/i18n/translate-config.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">翻译配置</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 翻译配置</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/security/online-upgrade.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">在线升级</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 在线升级</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/security/refresh-cache.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">刷新缓存</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 刷新缓存</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/security/system-log.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">系统日志</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 系统日志</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
13
pages/mall/admin/maintain/system-info.uvue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">系统信息</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text class="tip">TODO: 系统信息</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts"> </script> <style scoped> .page { padding: 16px; } .title { font-size: 18px; font-weight: 600; } .tip { color: #999; margin-top: 8px; display: block; } </style>
|
||||
|
||||
62
pages/mall/admin/marketing-management.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">营销管理</text>
|
||||
<text class="SubTitle">marketing-management</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<text>优惠券管理 - 占位页</text>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="uts">
|
||||
export default {}
|
||||
</script>
|
||||
<style>
|
||||
.page { padding: 30rpx; }
|
||||
</style>
|
||||
@@ -1,28 +1,62 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<text class="title">优惠券列表</text>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">优惠券列表</text>
|
||||
<text class="SubTitle">marketing/coupon/list</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// Minimal script
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +1,62 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<text class="title">用户领取记录</text>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">领取情况</text>
|
||||
<text class="SubTitle">marketing/coupon/receive</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// Minimal script
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +1,62 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<text class="title">积分管理</text>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">积分统计</text>
|
||||
<text class="SubTitle">marketing/points/index</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// Minimal script
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +1,62 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<text class="title">签到记录</text>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">签到奖励</text>
|
||||
<text class="SubTitle">marketing/signin/record</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// Minimal script
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +1,62 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<text class="title">签到规则</text>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">签到配置</text>
|
||||
<text class="SubTitle">marketing/signin/rule</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// Minimal script
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
padding: 40rpx;
|
||||
text-align: center;
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<text>商家管理 - 占位页</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page { padding: 30rpx; }
|
||||
</style>
|
||||
@@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<view class="merchant-review">
|
||||
<view class="page-header">
|
||||
<text class="page-title">商家入驻审核</text>
|
||||
<text class="page-subtitle">审核商家入驻申请</text>
|
||||
</view>
|
||||
|
||||
<view class="review-content">
|
||||
<text class="coming-soon">商家审核功能正在开发中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// 统一的导航方法
|
||||
const go = (url: string) => {
|
||||
// 1) 目标页面必须是非 tabBar 页面
|
||||
// 2) 必须在 pages.json / subPackages 注册
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.merchant-review {
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #212529;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
|
||||
.review-content {
|
||||
background-color: #fff;
|
||||
padding: 60rpx 40rpx;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.coming-soon {
|
||||
font-size: 28rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<text>通知中心 - 占位页</text>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="uts">
|
||||
export default {}
|
||||
</script>
|
||||
<style>
|
||||
.page { padding: 30rpx; }
|
||||
</style>
|
||||
62
pages/mall/admin/product-classification.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品分类</text>
|
||||
<text class="SubTitle">product-classification</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/product-labels.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品标签</text>
|
||||
<text class="SubTitle">product-labels</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/product-parameters.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品参数</text>
|
||||
<text class="SubTitle">product-parameters</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/product-protection.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品保障</text>
|
||||
<text class="SubTitle">product-protection</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<view class="product-review">
|
||||
<view class="page-header">
|
||||
<text class="page-title">商品审核</text>
|
||||
<text class="page-subtitle">审核商品上架申请</text>
|
||||
</view>
|
||||
|
||||
<view class="review-content">
|
||||
<text class="coming-soon">商品审核功能正在开发中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// 统一的导航方法
|
||||
const go = (url: string) => {
|
||||
// 1) 目标页面必须是非 tabBar 页面
|
||||
// 2) 必须在 pages.json / subPackages 注册
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.product-review {
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #212529;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
|
||||
.review-content {
|
||||
background-color: #fff;
|
||||
padding: 60rpx 40rpx;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.coming-soon {
|
||||
font-size: 28rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/product-reviews.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品评论</text>
|
||||
<text class="SubTitle">product-reviews</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/product-specifications.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品规格</text>
|
||||
<text class="SubTitle">product-specifications</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
62
pages/mall/admin/product-statistics.uvue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">商品统计</text>
|
||||
<text class="SubTitle">product-statistics</text>
|
||||
</view>
|
||||
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const params = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -1,872 +0,0 @@
|
||||
<template>
|
||||
<view class="admin-profile">
|
||||
<!-- 管理员信息头部 -->
|
||||
<view class="profile-header">
|
||||
<image :src="adminInfo.avatar_url || '/static/default-avatar.png'" class="admin-avatar" @click="editProfile" />
|
||||
<view class="admin-info">
|
||||
<text class="admin-name">{{ adminInfo.nickname || adminInfo.phone }}</text>
|
||||
<text class="admin-role">{{ getAdminRole() }}</text>
|
||||
<view class="admin-stats">
|
||||
<text class="stat-item">在线时长: {{ onlineHours }}h</text>
|
||||
<text class="stat-item">权限等级: {{ adminLevel }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="settings-icon" @click="goToSettings">⚙️</view>
|
||||
</view>
|
||||
|
||||
<!-- 系统概览 -->
|
||||
<view class="system-overview">
|
||||
<view class="section-title">系统概览</view>
|
||||
<view class="overview-grid">
|
||||
<view class="overview-card" @click="goToUsers">
|
||||
<text class="card-icon">👥</text>
|
||||
<text class="card-value">{{ systemStats.users }}</text>
|
||||
<text class="card-label">用户总数</text>
|
||||
<text class="card-change" :class="{ positive: systemStats.userGrowth > 0 }">
|
||||
{{ systemStats.userGrowth > 0 ? '+' : '' }}{{ systemStats.userGrowth }}%
|
||||
</text>
|
||||
</view>
|
||||
<view class="overview-card" @click="goToOrders">
|
||||
<text class="card-icon">📋</text>
|
||||
<text class="card-value">{{ systemStats.orders }}</text>
|
||||
<text class="card-label">订单总数</text>
|
||||
<text class="card-change" :class="{ positive: systemStats.orderGrowth > 0 }">
|
||||
{{ systemStats.orderGrowth > 0 ? '+' : '' }}{{ systemStats.orderGrowth }}%
|
||||
</text>
|
||||
</view>
|
||||
<view class="overview-card" @click="goToMerchants">
|
||||
<text class="card-icon">🏪</text>
|
||||
<text class="card-value">{{ systemStats.merchants }}</text>
|
||||
<text class="card-label">商家总数</text>
|
||||
<text class="card-change" :class="{ positive: systemStats.merchantGrowth > 0 }">
|
||||
{{ systemStats.merchantGrowth > 0 ? '+' : '' }}{{ systemStats.merchantGrowth }}%
|
||||
</text>
|
||||
</view>
|
||||
<view class="overview-card" @click="goToRevenue">
|
||||
<text class="card-icon">💰</text>
|
||||
<text class="card-value">¥{{ systemStats.revenue }}</text>
|
||||
<text class="card-label">总营收</text>
|
||||
<text class="card-change" :class="{ positive: systemStats.revenueGrowth > 0 }">
|
||||
{{ systemStats.revenueGrowth > 0 ? '+' : '' }}{{ systemStats.revenueGrowth }}%
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 待处理事项 -->
|
||||
<view class="pending-tasks">
|
||||
<view class="section-title">待处理事项</view>
|
||||
<view class="task-list">
|
||||
<view class="task-item urgent" @click="goToAudit('merchant')">
|
||||
<text class="task-icon">🏪</text>
|
||||
<view class="task-info">
|
||||
<text class="task-title">商家审核</text>
|
||||
<text class="task-desc">{{ pendingTasks.merchantAudit }}个商家待审核</text>
|
||||
</view>
|
||||
<text class="task-badge urgent">{{ pendingTasks.merchantAudit }}</text>
|
||||
</view>
|
||||
<view class="task-item" @click="goToComplaints">
|
||||
<text class="task-icon">📢</text>
|
||||
<view class="task-info">
|
||||
<text class="task-title">投诉处理</text>
|
||||
<text class="task-desc">{{ pendingTasks.complaints }}个投诉待处理</text>
|
||||
</view>
|
||||
<text class="task-badge">{{ pendingTasks.complaints }}</text>
|
||||
</view>
|
||||
<view class="task-item" @click="goToRefunds">
|
||||
<text class="task-icon">↩️</text>
|
||||
<view class="task-info">
|
||||
<text class="task-title">退款审核</text>
|
||||
<text class="task-desc">{{ pendingTasks.refunds }}个退款待审核</text>
|
||||
</view>
|
||||
<text class="task-badge">{{ pendingTasks.refunds }}</text>
|
||||
</view>
|
||||
<view class="task-item" @click="goToReports">
|
||||
<text class="task-icon">⚠️</text>
|
||||
<view class="task-info">
|
||||
<text class="task-title">举报处理</text>
|
||||
<text class="task-desc">{{ pendingTasks.reports }}个举报待处理</text>
|
||||
</view>
|
||||
<text class="task-badge">{{ pendingTasks.reports }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 今日数据 -->
|
||||
<view class="today-data">
|
||||
<view class="section-title">今日数据</view>
|
||||
<view class="data-grid">
|
||||
<view class="data-card">
|
||||
<text class="data-value">{{ todayData.newUsers }}</text>
|
||||
<text class="data-label">新增用户</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="data-value">{{ todayData.newOrders }}</text>
|
||||
<text class="data-label">新增订单</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="data-value">¥{{ todayData.revenue }}</text>
|
||||
<text class="data-label">平台收入</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="data-value">{{ todayData.activeUsers }}</text>
|
||||
<text class="data-label">活跃用户</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 系统健康状态 -->
|
||||
<view class="system-health">
|
||||
<view class="section-header">
|
||||
<text class="section-title">系统健康状态</text>
|
||||
<text class="view-more" @click="goToMonitor">详细监控 ></text>
|
||||
</view>
|
||||
<view class="health-grid">
|
||||
<view class="health-item">
|
||||
<text class="health-label">服务器状态</text>
|
||||
<view class="health-status">
|
||||
<view class="status-dot" :class="{ online: systemHealth.server }"></view>
|
||||
<text class="status-text">{{ systemHealth.server ? '正常' : '异常' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="health-item">
|
||||
<text class="health-label">数据库状态</text>
|
||||
<view class="health-status">
|
||||
<view class="status-dot" :class="{ online: systemHealth.database }"></view>
|
||||
<text class="status-text">{{ systemHealth.database ? '正常' : '异常' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="health-item">
|
||||
<text class="health-label">缓存状态</text>
|
||||
<view class="health-status">
|
||||
<view class="status-dot" :class="{ online: systemHealth.cache }"></view>
|
||||
<text class="status-text">{{ systemHealth.cache ? '正常' : '异常' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="health-item">
|
||||
<text class="health-label">支付服务</text>
|
||||
<view class="health-status">
|
||||
<view class="status-dot" :class="{ online: systemHealth.payment }"></view>
|
||||
<text class="status-text">{{ systemHealth.payment ? '正常' : '异常' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近操作记录 -->
|
||||
<view class="recent-operations">
|
||||
<view class="section-header">
|
||||
<text class="section-title">最近操作</text>
|
||||
<text class="view-all" @click="goToOperationLogs">查看全部 ></text>
|
||||
</view>
|
||||
<view v-if="recentOperations.length > 0" class="operation-list">
|
||||
<view v-for="operation in recentOperations" :key="operation.id" class="operation-item">
|
||||
<view class="operation-info">
|
||||
<text class="operation-title">{{ operation.title }}</text>
|
||||
<text class="operation-desc">{{ operation.description }}</text>
|
||||
</view>
|
||||
<text class="operation-time">{{ formatTime(operation.created_at) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="no-data">
|
||||
<text class="no-data-text">暂无操作记录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快捷功能 -->
|
||||
<view class="quick-functions">
|
||||
<view class="section-title">快捷功能</view>
|
||||
<view class="function-grid">
|
||||
<view class="function-item" @click="goToUserManagement">
|
||||
<text class="function-icon">👥</text>
|
||||
<text class="function-label">用户管理</text>
|
||||
</view>
|
||||
<view class="function-item" @click="goToMerchantManagement">
|
||||
<text class="function-icon">🏪</text>
|
||||
<text class="function-label">商家管理</text>
|
||||
</view>
|
||||
<view class="function-item" @click="goToProductManagement">
|
||||
<text class="function-icon">📦</text>
|
||||
<text class="function-label">商品管理</text>
|
||||
</view>
|
||||
<view class="function-item" @click="goToOrderManagement">
|
||||
<text class="function-icon">📋</text>
|
||||
<text class="function-label">订单管理</text>
|
||||
</view>
|
||||
<view class="function-item" @click="goToFinanceManagement">
|
||||
<text class="function-icon">💰</text>
|
||||
<text class="function-label">财务管理</text>
|
||||
</view>
|
||||
<view class="function-item" @click="goToSystemSettings">
|
||||
<text class="function-icon">⚙️</text>
|
||||
<text class="function-label">系统设置</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="function-menu">
|
||||
<view class="menu-group">
|
||||
<view class="menu-item" @click="goToReports">
|
||||
<text class="menu-icon">📊</text>
|
||||
<text class="menu-label">数据报表</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="goToAnnouncements">
|
||||
<text class="menu-icon">📢</text>
|
||||
<text class="menu-label">公告管理</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="goToPermissions">
|
||||
<text class="menu-icon">🔐</text>
|
||||
<text class="menu-label">权限管理</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-group">
|
||||
<view class="menu-item" @click="goToHelp">
|
||||
<text class="menu-icon">❓</text>
|
||||
<text class="menu-label">帮助中心</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="goToFeedback">
|
||||
<text class="menu-icon">💬</text>
|
||||
<text class="menu-label">意见反馈</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import type { UserType, ApiResponseType } from '@/types/mall-types'
|
||||
|
||||
// 响应式数据
|
||||
const adminInfo = ref({
|
||||
id: '',
|
||||
phone: '',
|
||||
nickname: '系统管理员',
|
||||
avatar_url: ''
|
||||
} as UserType)
|
||||
|
||||
const onlineHours = ref(8.5)
|
||||
const adminLevel = ref('超级管理员')
|
||||
|
||||
const systemStats = ref({
|
||||
users: '12,568',
|
||||
userGrowth: 12.5,
|
||||
orders: '8,932',
|
||||
orderGrowth: 8.3,
|
||||
merchants: '1,234',
|
||||
merchantGrowth: 5.2,
|
||||
revenue: '1,256,789',
|
||||
revenueGrowth: 15.8
|
||||
})
|
||||
|
||||
const pendingTasks = ref({
|
||||
merchantAudit: 8,
|
||||
complaints: 15,
|
||||
refunds: 12,
|
||||
reports: 6
|
||||
})
|
||||
|
||||
const todayData = ref({
|
||||
newUsers: 156,
|
||||
newOrders: 289,
|
||||
revenue: '25,680',
|
||||
activeUsers: 3456
|
||||
})
|
||||
|
||||
const systemHealth = ref({
|
||||
server: true,
|
||||
database: true,
|
||||
cache: true,
|
||||
payment: true
|
||||
})
|
||||
|
||||
const recentOperations = ref([
|
||||
{
|
||||
id: 'op001',
|
||||
title: '商家审核通过',
|
||||
description: '审核通过商家"时尚服饰专营店"',
|
||||
created_at: '2024-12-01 14:30:00'
|
||||
},
|
||||
{
|
||||
id: 'op002',
|
||||
title: '处理用户投诉',
|
||||
description: '处理订单#ORD20241201001投诉',
|
||||
created_at: '2024-12-01 13:45:00'
|
||||
},
|
||||
{
|
||||
id: 'op003',
|
||||
title: '系统配置更新',
|
||||
description: '更新了支付配置参数',
|
||||
created_at: '2024-12-01 12:20:00'
|
||||
}
|
||||
])
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadAdminInfo()
|
||||
loadSystemStats()
|
||||
loadPendingTasks()
|
||||
})
|
||||
|
||||
// 方法
|
||||
function loadAdminInfo() {
|
||||
// 模拟加载管理员信息
|
||||
adminInfo.value = {
|
||||
id: 'admin001',
|
||||
phone: '13900000000',
|
||||
email: 'admin@mall.com',
|
||||
nickname: '超级管理员',
|
||||
avatar_url: '/static/admin-avatar.png',
|
||||
gender: 0,
|
||||
user_type: 99,
|
||||
status: 1,
|
||||
created_at: '2024-01-01'
|
||||
}
|
||||
}
|
||||
|
||||
function loadSystemStats() {
|
||||
// 模拟加载系统统计
|
||||
// 实际应用中从API获取
|
||||
}
|
||||
|
||||
function loadPendingTasks() {
|
||||
// 模拟加载待处理任务
|
||||
// 实际应用中从API获取
|
||||
}
|
||||
|
||||
function getAdminRole(): string {
|
||||
const roleMap = {
|
||||
99: '超级管理员',
|
||||
98: '系统管理员',
|
||||
97: '运营管理员'
|
||||
}
|
||||
return roleMap[adminInfo.value.user_type] || '管理员'
|
||||
}
|
||||
|
||||
function formatTime(dateStr: string): string {
|
||||
const date = new Date(dateStr)
|
||||
const now = new Date()
|
||||
const diff = now.getTime() - date.getTime()
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
|
||||
if (hours < 1) {
|
||||
return '刚刚'
|
||||
} else if (hours < 24) {
|
||||
return `${hours}小时前`
|
||||
} else {
|
||||
return `${Math.floor(hours / 24)}天前`
|
||||
}
|
||||
}
|
||||
|
||||
// 导航方法
|
||||
function editProfile() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/profile-edit'
|
||||
})
|
||||
}
|
||||
|
||||
function goToSettings() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/settings'
|
||||
})
|
||||
}
|
||||
|
||||
function goToUsers() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/users'
|
||||
})
|
||||
}
|
||||
|
||||
function goToOrders() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/orders'
|
||||
})
|
||||
}
|
||||
|
||||
function goToMerchants() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/merchants'
|
||||
})
|
||||
}
|
||||
|
||||
function goToRevenue() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/revenue'
|
||||
})
|
||||
}
|
||||
|
||||
function goToAudit(type: string) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/admin/audit?type=${type}`
|
||||
})
|
||||
}
|
||||
|
||||
function goToComplaints() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/complaints'
|
||||
})
|
||||
}
|
||||
|
||||
function goToRefunds() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/refunds'
|
||||
})
|
||||
}
|
||||
|
||||
function goToReports() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/reports'
|
||||
})
|
||||
}
|
||||
|
||||
function goToMonitor() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/monitor'
|
||||
})
|
||||
}
|
||||
|
||||
function goToOperationLogs() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/operation-logs'
|
||||
})
|
||||
}
|
||||
|
||||
function goToUserManagement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/user-management'
|
||||
})
|
||||
}
|
||||
|
||||
function goToMerchantManagement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/merchant-management'
|
||||
})
|
||||
}
|
||||
|
||||
function goToProductManagement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/product-management'
|
||||
})
|
||||
}
|
||||
|
||||
function goToOrderManagement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/order-management'
|
||||
})
|
||||
}
|
||||
|
||||
function goToFinanceManagement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/finance-management'
|
||||
})
|
||||
}
|
||||
|
||||
function goToSystemSettings() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/system-settings'
|
||||
})
|
||||
}
|
||||
|
||||
function goToAnnouncements() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/announcements'
|
||||
})
|
||||
}
|
||||
|
||||
function goToPermissions() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/admin/permissions'
|
||||
})
|
||||
}
|
||||
|
||||
function goToHelp() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/common/help'
|
||||
})
|
||||
}
|
||||
|
||||
function goToFeedback() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/common/feedback'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.admin-profile {
|
||||
padding: 0 0 120rpx 0;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 40rpx 30rpx;
|
||||
background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.admin-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
margin-right: 30rpx;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.admin-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.admin-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.admin-role {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.admin-stats {
|
||||
display: flex;
|
||||
gap: 30rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.settings-icon {
|
||||
font-size: 36rpx;
|
||||
color: white;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.system-overview, .pending-tasks, .today-data, .system-health, .recent-operations, .quick-functions, .function-menu {
|
||||
margin: 20rpx 30rpx;
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.view-all, .view-more {
|
||||
font-size: 24rpx;
|
||||
color: #a29bfe;
|
||||
}
|
||||
|
||||
.overview-grid {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.overview-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 150rpx;
|
||||
padding: 25rpx 15rpx;
|
||||
background: linear-gradient(135deg, #f8f9ff 0%, #e8ecff 100%);
|
||||
border-radius: 20rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
font-size: 48rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.card-change {
|
||||
font-size: 20rpx;
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
.card-change.positive {
|
||||
color: #00b894;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #f8f9ff;
|
||||
border-radius: 15rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.task-item.urgent {
|
||||
border-left: 6rpx solid #ff6b6b;
|
||||
}
|
||||
|
||||
.task-icon {
|
||||
font-size: 36rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.task-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.task-desc {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-badge {
|
||||
background: #a29bfe;
|
||||
color: white;
|
||||
font-size: 20rpx;
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 15rpx;
|
||||
min-width: 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.task-badge.urgent {
|
||||
background: #ff6b6b;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.1); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.data-grid {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.data-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 150rpx;
|
||||
padding: 20rpx;
|
||||
background: #f8f9ff;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
|
||||
.data-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #a29bfe;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.data-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.health-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.health-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #f8f9ff;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
|
||||
.health-label {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.health-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: #ff6b6b;
|
||||
}
|
||||
|
||||
.status-dot.online {
|
||||
background: #00b894;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.operation-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.operation-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx;
|
||||
background: #f8f9ff;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
|
||||
.operation-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.operation-title {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.operation-desc {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.operation-time {
|
||||
font-size: 20rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.function-grid {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.function-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 140rpx;
|
||||
padding: 25rpx 15rpx;
|
||||
background: #f8f9ff;
|
||||
border-radius: 15rpx;
|
||||
}
|
||||
|
||||
.function-icon {
|
||||
font-size: 48rpx;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.function-label {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.menu-group {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.menu-group:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 25rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 36rpx;
|
||||
width: 60rpx;
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.no-data-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
@@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<view class="refund-review">
|
||||
<view class="page-header">
|
||||
<text class="page-title">退款审核</text>
|
||||
<text class="page-subtitle">审核用户退款申请</text>
|
||||
</view>
|
||||
|
||||
<view class="review-content">
|
||||
<text class="coming-soon">退款审核功能正在开发中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
// 统一的导航方法
|
||||
const go = (url: string) => {
|
||||
// 1) 目标页面必须是非 tabBar 页面
|
||||
// 2) 必须在 pages.json / subPackages 注册
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.refund-review {
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background-color: #fff;
|
||||
padding: 40rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #212529;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
|
||||
.review-content {
|
||||
background-color: #fff;
|
||||
padding: 60rpx 40rpx;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.coming-soon {
|
||||
font-size: 28rpx;
|
||||
color: #6c757d;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
81
pages/mall/admin/system/agreement-settings.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">协议设置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">协议设置</text>
|
||||
<text class="p">TODO:在这里实现 协议设置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/collect.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">商品采集配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">商品采集配置</text>
|
||||
<text class="p">TODO:在这里实现 商品采集配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/logistics.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">物流查询配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">物流查询配置</text>
|
||||
<text class="p">TODO:在这里实现 物流查询配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/pay.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">商城支付配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">商城支付配置</text>
|
||||
<text class="p">TODO:在这里实现 商城支付配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/sms.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">短信接口配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">短信接口配置</text>
|
||||
<text class="p">TODO:在这里实现 短信接口配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/storage.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">系统存储配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">系统存储配置</text>
|
||||
<text class="p">TODO:在这里实现 系统存储配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/waybill.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">电子面单配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">电子面单配置</text>
|
||||
<text class="p">TODO:在这里实现 电子面单配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/yht/config.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">一号通配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">一号通配置</text>
|
||||
<text class="p">TODO:在这里实现 一号通配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/api/yht/page.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">一号通页面</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">一号通页面</text>
|
||||
<text class="p">TODO:在这里实现 一号通页面 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/message-management.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">消息管理</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">消息管理</text>
|
||||
<text class="p">TODO:在这里实现 消息管理 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/permission/admin-list.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">管理员列表</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">管理员列表</text>
|
||||
<text class="p">TODO:在这里实现 管理员列表 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/permission/permission-setting.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">权限设置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">权限设置</text>
|
||||
<text class="p">TODO:在这里实现 权限设置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/permission/role.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">角色管理</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">角色管理</text>
|
||||
<text class="p">TODO:在这里实现 角色管理 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/receipt-settings.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">小票配置</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">小票配置</text>
|
||||
<text class="p">TODO:在这里实现 小票配置 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/shipping/courier.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">配送员管理</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">配送员管理</text>
|
||||
<text class="p">TODO:在这里实现 配送员管理 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/shipping/freight-template.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">运费模板</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">运费模板</text>
|
||||
<text class="p">TODO:在这里实现 运费模板 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/shipping/pickup/points.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">提货点</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">提货点</text>
|
||||
<text class="p">TODO:在这里实现 提货点 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
81
pages/mall/admin/system/shipping/pickup/verifiers.uvue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- TopBar (navigationStyle: custom 时需要自己做顶部栏) -->
|
||||
<view class="topbar">
|
||||
<view class="status-bar" />
|
||||
<view class="nav">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<text class="nav-icon">‹</text>
|
||||
<text class="nav-text">返回</text>
|
||||
</view>
|
||||
|
||||
<text class="nav-title">核销员</text>
|
||||
|
||||
<view class="nav-right">
|
||||
<text class="nav-action" @click="onPrimaryAction">保存</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Main -->
|
||||
<scroll-view class="body" scroll-y="true">
|
||||
<view class="container">
|
||||
<view class="card">
|
||||
<text class="h2">核销员</text>
|
||||
<text class="p">TODO:在这里实现 核销员 的页面内容。</text>
|
||||
<view class="divider" />
|
||||
<text class="p muted">提示:当前为可跑的占位模板(TopBar + Container + Card)。</text>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<text class="h3">建议你下一步先补齐</text>
|
||||
<view class="list">
|
||||
<text class="li">1)接口:拉取/保存数据(API 协议对齐后端)</text>
|
||||
<text class="li">2)列表/表单:搜索、分页、增删改</text>
|
||||
<text class="li">3)权限:按钮/路由级权限控制</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
const goBack = () => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const onPrimaryAction = () => {
|
||||
uni.showToast({ title: 'TODO:保存逻辑', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { width: 100%; height: 100%; background-color: #f6f7fb; }
|
||||
|
||||
/* 顶部栏(适配沉浸式状态栏) */
|
||||
.topbar { position: sticky; top: 0; z-index: 10; background-color: #fff; }
|
||||
.status-bar { height: var(--status-bar-height); }
|
||||
.nav { height: 44px; display: flex; align-items: center; padding: 0 12px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #eef0f5; }
|
||||
.nav-left { width: 88px; display: flex; align-items: center; }
|
||||
.nav-icon { font-size: 22px; margin-right: 4px; color: #111; }
|
||||
.nav-text { font-size: 14px; color: #111; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 16px; font-weight: 600; color: #111; }
|
||||
.nav-right { width: 88px; display: flex; justify-content: flex-end; }
|
||||
.nav-action { font-size: 14px; color: #1677ff; }
|
||||
|
||||
.body { height: calc(100vh - 44px - var(--status-bar-height)); }
|
||||
.container { padding: 12px; }
|
||||
|
||||
.card { background-color: #fff; border-radius: 12px; padding: 14px; margin-bottom: 12px; box-shadow: 0 6px 18px rgba(17, 24, 39, 0.06); }
|
||||
|
||||
.h2 { font-size: 18px; font-weight: 700; color: #111; }
|
||||
.h3 { font-size: 16px; font-weight: 600; color: #111; margin-bottom: 8px; }
|
||||
.p { font-size: 13px; color: #333; margin-top: 8px; line-height: 18px; }
|
||||
.muted { color: #8892a6; }
|
||||
|
||||
.divider { height: 1px; background-color: #eef0f5; margin: 12px 0; }
|
||||
|
||||
.list { margin-top: 8px; }
|
||||
.li { font-size: 13px; color: #333; line-height: 20px; }
|
||||
</style>
|
||||
@@ -1,907 +0,0 @@
|
||||
<template>
|
||||
<view class="user-detail-page">
|
||||
<!-- 用户基本信息 -->
|
||||
<view class="user-profile">
|
||||
<view class="profile-header">
|
||||
<image :src="user.avatar_url || '/static/default-avatar.png'" class="user-avatar" />
|
||||
<view class="user-basic">
|
||||
<text class="user-name">{{ user.nickname || user.phone }}</text>
|
||||
<text class="user-id">ID: {{ user.id }}</text>
|
||||
<view class="user-status">
|
||||
<text class="status-badge" :class="{ active: user.status === 1, inactive: user.status === 0 }">
|
||||
{{ user.status === 1 ? '正常' : '冻结' }}
|
||||
</text>
|
||||
<text class="user-type">{{ getUserTypeText() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="action-menu" @click="showActionMenu">⋮</view>
|
||||
</view>
|
||||
|
||||
<view class="profile-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">手机号码</text>
|
||||
<text class="detail-value">{{ user.phone }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">邮箱地址</text>
|
||||
<text class="detail-value">{{ user.email || '未设置' }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">性别</text>
|
||||
<text class="detail-value">{{ getGenderText() }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">注册时间</text>
|
||||
<text class="detail-value">{{ formatTime(user.created_at) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户统计 -->
|
||||
<view class="user-stats">
|
||||
<view class="section-title">用户统计</view>
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ userStats.total_orders }}</text>
|
||||
<text class="stat-label">总订单数</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">¥{{ userStats.total_amount }}</text>
|
||||
<text class="stat-label">消费总额</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ userStats.total_reviews }}</text>
|
||||
<text class="stat-label">评价数量</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ userStats.avg_rating.toFixed(1) }}</text>
|
||||
<text class="stat-label">平均评分</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近订单 -->
|
||||
<view class="recent-orders">
|
||||
<view class="section-header">
|
||||
<text class="section-title">最近订单</text>
|
||||
<text class="view-all" @click="viewAllOrders">查看全部</text>
|
||||
</view>
|
||||
|
||||
<view v-if="recentOrders.length === 0" class="empty-orders">
|
||||
<text class="empty-text">暂无订单记录</text>
|
||||
</view>
|
||||
|
||||
<view v-for="order in recentOrders" :key="order.id" class="order-item" @click="viewOrderDetail(order)">
|
||||
<view class="order-header">
|
||||
<text class="order-no">{{ order.order_no }}</text>
|
||||
<text class="order-status" :class="getOrderStatusClass(order.status)">{{ getOrderStatusText(order.status) }}</text>
|
||||
</view>
|
||||
<view class="order-info">
|
||||
<text class="order-amount">¥{{ order.actual_amount }}</text>
|
||||
<text class="order-time">{{ formatTime(order.created_at) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户行为记录 -->
|
||||
<view class="user-activities">
|
||||
<view class="section-header">
|
||||
<text class="section-title">行为记录</text>
|
||||
<text class="view-all" @click="viewAllActivities">查看全部</text>
|
||||
</view>
|
||||
|
||||
<view v-for="activity in userActivities" :key="activity.id" class="activity-item">
|
||||
<view class="activity-icon" :class="activity.type">{{ getActivityIcon(activity.type) }}</view>
|
||||
<view class="activity-content">
|
||||
<text class="activity-desc">{{ activity.description }}</text>
|
||||
<text class="activity-time">{{ formatTime(activity.created_at) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 风险评估 -->
|
||||
<view class="risk-assessment">
|
||||
<view class="section-title">风险评估</view>
|
||||
<view class="risk-score">
|
||||
<view class="score-circle" :class="getRiskLevel()">
|
||||
<text class="score-value">{{ riskData.score }}</text>
|
||||
<text class="score-max">/100</text>
|
||||
</view>
|
||||
<view class="risk-info">
|
||||
<text class="risk-level">{{ getRiskLevelText() }}</text>
|
||||
<text class="risk-desc">{{ getRiskDescription() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="risk-factors">
|
||||
<view v-for="factor in riskData.factors" :key="factor.type" class="factor-item">
|
||||
<text class="factor-label">{{ factor.label }}</text>
|
||||
<view class="factor-bar">
|
||||
<view class="factor-fill" :style="{ width: factor.value + '%' }" :class="factor.level"></view>
|
||||
</view>
|
||||
<text class="factor-value">{{ factor.value }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作记录 -->
|
||||
<view class="admin-logs">
|
||||
<view class="section-header">
|
||||
<text class="section-title">操作记录</text>
|
||||
<text class="add-log" @click="addAdminLog">添加记录</text>
|
||||
</view>
|
||||
|
||||
<view v-for="log in adminLogs" :key="log.id" class="log-item">
|
||||
<view class="log-content">
|
||||
<text class="log-action">{{ log.action }}</text>
|
||||
<text class="log-reason">{{ log.reason }}</text>
|
||||
</view>
|
||||
<view class="log-meta">
|
||||
<text class="log-admin">{{ log.admin_name }}</text>
|
||||
<text class="log-time">{{ formatTime(log.created_at) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作菜单弹窗 -->
|
||||
<view v-if="showMenu" class="action-modal" @click="hideActionMenu">
|
||||
<view class="action-list" @click.stop>
|
||||
<view class="action-item" @click="toggleUserStatus">
|
||||
{{ user.status === 1 ? '冻结用户' : '解冻用户' }}
|
||||
</view>
|
||||
<view class="action-item" @click="resetPassword">重置密码</view>
|
||||
<view class="action-item" @click="sendMessage">发送消息</view>
|
||||
<view class="action-item danger" @click="deleteUser">删除用户</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { UserType, OrderType } from '@/types/mall-types.uts'
|
||||
|
||||
type UserStatsType = {
|
||||
total_orders: number
|
||||
total_amount: number
|
||||
total_reviews: number
|
||||
avg_rating: number
|
||||
}
|
||||
|
||||
type UserActivityType = {
|
||||
id: string
|
||||
type: string
|
||||
description: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
type RiskFactorType = {
|
||||
type: string
|
||||
label: string
|
||||
value: number
|
||||
level: string
|
||||
}
|
||||
|
||||
type RiskDataType = {
|
||||
score: number
|
||||
level: string
|
||||
factors: Array<RiskFactorType>
|
||||
}
|
||||
|
||||
type AdminLogType = {
|
||||
id: string
|
||||
action: string
|
||||
reason: string
|
||||
admin_name: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
user: {
|
||||
id: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
nickname: '',
|
||||
avatar_url: '',
|
||||
gender: 0,
|
||||
user_type: 0,
|
||||
status: 0,
|
||||
created_at: ''
|
||||
} as UserType,
|
||||
userStats: {
|
||||
total_orders: 0,
|
||||
total_amount: 0,
|
||||
total_reviews: 0,
|
||||
avg_rating: 0
|
||||
} as UserStatsType,
|
||||
recentOrders: [] as Array<OrderType>,
|
||||
userActivities: [] as Array<UserActivityType>,
|
||||
riskData: {
|
||||
score: 0,
|
||||
level: '',
|
||||
factors: []
|
||||
} as RiskDataType,
|
||||
adminLogs: [] as Array<AdminLogType>,
|
||||
showMenu: false
|
||||
}
|
||||
},
|
||||
onLoad(options: any) {
|
||||
const userId = options.userId as string
|
||||
if (userId) {
|
||||
this.loadUserDetail(userId)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadUserDetail(userId: string) {
|
||||
// 模拟加载用户详情数据
|
||||
this.user = {
|
||||
id: userId,
|
||||
phone: '13800138000',
|
||||
email: 'user@example.com',
|
||||
nickname: '张三',
|
||||
avatar_url: '/static/avatar1.jpg',
|
||||
gender: 1,
|
||||
user_type: 1,
|
||||
status: 1,
|
||||
created_at: '2023-06-15T10:30:00'
|
||||
}
|
||||
|
||||
this.userStats = {
|
||||
total_orders: 23,
|
||||
total_amount: 5680.50,
|
||||
total_reviews: 18,
|
||||
avg_rating: 4.3
|
||||
}
|
||||
|
||||
this.recentOrders = [
|
||||
{
|
||||
id: 'order_001',
|
||||
order_no: 'ORD202401150001',
|
||||
user_id: userId,
|
||||
merchant_id: 'merchant_001',
|
||||
status: 4,
|
||||
total_amount: 299.98,
|
||||
discount_amount: 30.00,
|
||||
delivery_fee: 8.00,
|
||||
actual_amount: 277.98,
|
||||
payment_method: 1,
|
||||
payment_status: 1,
|
||||
delivery_address: {},
|
||||
created_at: '2024-01-15T14:30:00'
|
||||
}
|
||||
]
|
||||
|
||||
this.userActivities = [
|
||||
{
|
||||
id: 'activity_001',
|
||||
type: 'login',
|
||||
description: '用户登录系统',
|
||||
created_at: '2024-01-15T09:30:00'
|
||||
},
|
||||
{
|
||||
id: 'activity_002',
|
||||
type: 'order',
|
||||
description: '创建订单 ORD202401150001',
|
||||
created_at: '2024-01-15T14:30:00'
|
||||
},
|
||||
{
|
||||
id: 'activity_003',
|
||||
type: 'review',
|
||||
description: '对商品进行评价',
|
||||
created_at: '2024-01-14T16:20:00'
|
||||
}
|
||||
]
|
||||
|
||||
this.riskData = {
|
||||
score: 25,
|
||||
level: 'low',
|
||||
factors: [
|
||||
{ type: 'refund', label: '退款率', value: 15, level: 'low' },
|
||||
{ type: 'complaint', label: '投诉率', value: 5, level: 'low' },
|
||||
{ type: 'chargeback', label: '拒付率', value: 0, level: 'low' },
|
||||
{ type: 'fraud', label: '欺诈风险', value: 10, level: 'low' }
|
||||
]
|
||||
}
|
||||
|
||||
this.adminLogs = [
|
||||
{
|
||||
id: 'log_001',
|
||||
action: '账户验证',
|
||||
reason: '用户实名认证通过',
|
||||
admin_name: '管理员小李',
|
||||
created_at: '2024-01-10T11:00:00'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
getUserTypeText(): string {
|
||||
const types = ['普通用户', '普通用户', '商家用户', '配送员', '管理员']
|
||||
return types[this.user.user_type] || '未知'
|
||||
},
|
||||
|
||||
getGenderText(): string {
|
||||
const genders = ['未知', '男', '女']
|
||||
return genders[this.user.gender] || '未知'
|
||||
},
|
||||
|
||||
getOrderStatusText(status: number): string {
|
||||
const statusTexts = ['异常', '待支付', '待发货', '待收货', '已完成', '已取消']
|
||||
return statusTexts[status] || '未知'
|
||||
},
|
||||
|
||||
getOrderStatusClass(status: number): string {
|
||||
const statusClasses = ['error', 'pending', 'processing', 'shipping', 'completed', 'cancelled']
|
||||
return statusClasses[status] || 'error'
|
||||
},
|
||||
|
||||
getActivityIcon(type: string): string {
|
||||
const icons: Record<string, string> = {
|
||||
login: '🔐',
|
||||
order: '🛍️',
|
||||
review: '⭐',
|
||||
refund: '💰',
|
||||
complaint: '⚠️'
|
||||
}
|
||||
return icons[type] || '📝'
|
||||
},
|
||||
|
||||
getRiskLevel(): string {
|
||||
if (this.riskData.score < 30) return 'low'
|
||||
if (this.riskData.score < 70) return 'medium'
|
||||
return 'high'
|
||||
},
|
||||
|
||||
getRiskLevelText(): string {
|
||||
const level = this.getRiskLevel()
|
||||
const levelTexts: Record<string, string> = {
|
||||
low: '低风险',
|
||||
medium: '中风险',
|
||||
high: '高风险'
|
||||
}
|
||||
return levelTexts[level] || '未知'
|
||||
},
|
||||
|
||||
getRiskDescription(): string {
|
||||
const level = this.getRiskLevel()
|
||||
const descriptions: Record<string, string> = {
|
||||
low: '用户行为正常,风险较低',
|
||||
medium: '存在一定风险,需要关注',
|
||||
high: '高风险用户,建议重点监控'
|
||||
}
|
||||
return descriptions[level] || ''
|
||||
},
|
||||
|
||||
formatTime(timeStr: string): string {
|
||||
return timeStr.replace('T', ' ').split('.')[0]
|
||||
},
|
||||
|
||||
showActionMenu() {
|
||||
this.showMenu = true
|
||||
},
|
||||
|
||||
hideActionMenu() {
|
||||
this.showMenu = false
|
||||
},
|
||||
|
||||
toggleUserStatus() {
|
||||
const action = this.user.status === 1 ? '冻结' : '解冻'
|
||||
uni.showModal({
|
||||
title: `${action}用户`,
|
||||
content: `确定要${action}用户 ${this.user.nickname} 吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.user.status = this.user.status === 1 ? 0 : 1
|
||||
this.hideActionMenu()
|
||||
uni.showToast({
|
||||
title: `${action}成功`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
resetPassword() {
|
||||
uni.showModal({
|
||||
title: '重置密码',
|
||||
content: '确定要重置用户密码吗?新密码将发送到用户手机。',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.hideActionMenu()
|
||||
uni.showToast({
|
||||
title: '密码重置成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
sendMessage() {
|
||||
this.hideActionMenu()
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/admin/send-message?userId=${this.user.id}`
|
||||
})
|
||||
},
|
||||
|
||||
deleteUser() {
|
||||
uni.showModal({
|
||||
title: '删除用户',
|
||||
content: '删除用户将无法恢复,确定要删除吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.hideActionMenu()
|
||||
uni.showToast({
|
||||
title: '用户已删除',
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
viewAllOrders() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/admin/user-orders?userId=${this.user.id}`
|
||||
})
|
||||
},
|
||||
|
||||
viewOrderDetail(order: OrderType) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/admin/order-detail?orderId=${order.id}`
|
||||
})
|
||||
},
|
||||
|
||||
viewAllActivities() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/admin/user-activities?userId=${this.user.id}`
|
||||
})
|
||||
},
|
||||
|
||||
addAdminLog() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/admin/add-log?userId=${this.user.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.user-detail-page {
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.user-profile, .user-stats, .recent-orders, .user-activities, .risk-assessment, .admin-logs {
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
|
||||
.user-basic {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.user-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15rpx;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.status-badge.active {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.status-badge.inactive {
|
||||
background-color: #ff4444;
|
||||
}
|
||||
|
||||
.user-type {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
background-color: #f0f0f0;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.action-menu {
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.profile-details {
|
||||
border-top: 1rpx solid #f5f5f5;
|
||||
padding-top: 25rpx;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 0;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
width: 150rpx;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 25rpx;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 25rpx;
|
||||
}
|
||||
|
||||
.view-all, .add-log {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 30rpx 0;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.empty-orders {
|
||||
text-align: center;
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.order-item, .log-item {
|
||||
padding: 25rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.order-item:last-child, .log-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.order-no {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
font-size: 22rpx;
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 10rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.order-status.pending {
|
||||
background-color: #ffa726;
|
||||
}
|
||||
|
||||
.order-status.processing {
|
||||
background-color: #2196f3;
|
||||
}
|
||||
|
||||
.order-status.shipping {
|
||||
background-color: #9c27b0;
|
||||
}
|
||||
|
||||
.order-status.completed {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.order-status.cancelled {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.order-amount {
|
||||
font-size: 24rpx;
|
||||
color: #ff4444;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.order-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.activity-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
font-size: 28rpx;
|
||||
margin-right: 15rpx;
|
||||
margin-top: 5rpx;
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.activity-desc {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.risk-score {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.score-circle {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 30rpx;
|
||||
border: 6rpx solid;
|
||||
}
|
||||
|
||||
.score-circle.low {
|
||||
border-color: #4caf50;
|
||||
background-color: #e8f5e8;
|
||||
}
|
||||
|
||||
.score-circle.medium {
|
||||
border-color: #ffa726;
|
||||
background-color: #fff8e1;
|
||||
}
|
||||
|
||||
.score-circle.high {
|
||||
border-color: #ff4444;
|
||||
background-color: #ffebee;
|
||||
}
|
||||
|
||||
.score-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.score-max {
|
||||
font-size: 20rpx;
|
||||
color: #666;
|
||||
margin-top: -5rpx;
|
||||
}
|
||||
|
||||
.risk-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.risk-level {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.risk-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.risk-factors {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.factor-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.factor-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
width: 120rpx;
|
||||
}
|
||||
|
||||
.factor-bar {
|
||||
flex: 1;
|
||||
height: 12rpx;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 6rpx;
|
||||
margin: 0 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.factor-fill {
|
||||
height: 100%;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
|
||||
.factor-fill.low {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.factor-fill.medium {
|
||||
background-color: #ffa726;
|
||||
}
|
||||
|
||||
.factor-fill.high {
|
||||
background-color: #ff4444;
|
||||
}
|
||||
|
||||
.factor-value {
|
||||
font-size: 22rpx;
|
||||
color: #333;
|
||||
width: 60rpx;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.log-action {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.log-reason {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.log-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.log-admin {
|
||||
font-size: 22rpx;
|
||||
color: #007aff;
|
||||
}
|
||||
|
||||
.log-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.action-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.action-list {
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx 0;
|
||||
margin: 0 60rpx;
|
||||
max-width: 500rpx;
|
||||
}
|
||||
|
||||
.action-item {
|
||||
padding: 25rpx 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.action-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.action-item.danger {
|
||||
color: #ff4444;
|
||||
}
|
||||
</style>
|
||||
@@ -1,772 +1,62 @@
|
||||
<template>
|
||||
<AdminLayout current-page="statistics">
|
||||
<view class="user-statistics-page">
|
||||
<!-- 筛选条件栏 -->
|
||||
<view class="filter-section">
|
||||
<view class="filter-row">
|
||||
<view class="filter-left">
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">用户渠道:</text>
|
||||
<picker
|
||||
mode="selector"
|
||||
:range="channelOptions"
|
||||
:value="selectedChannel"
|
||||
@change="handleChannelChange"
|
||||
>
|
||||
<view class="filter-select">
|
||||
<text>{{ channelOptions[selectedChannel] }}</text>
|
||||
<text class="iconfont icon-down"></text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="Page">
|
||||
<view class="Header">
|
||||
<text class="Title">用户统计</text>
|
||||
<text class="SubTitle">user-statistics</text>
|
||||
</view>
|
||||
|
||||
<view class="filter-item">
|
||||
<text class="filter-label">日期范围:</text>
|
||||
<view class="date-range">
|
||||
<picker
|
||||
mode="date"
|
||||
:value="startDate"
|
||||
:start="minDate"
|
||||
:end="maxDate"
|
||||
@change="handleStartDateChange"
|
||||
>
|
||||
<view class="date-input">
|
||||
<text>{{ startDate || '开始日期' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<text class="date-separator">-</text>
|
||||
<picker
|
||||
mode="date"
|
||||
:value="endDate"
|
||||
:start="minDate"
|
||||
:end="maxDate"
|
||||
@change="handleEndDateChange"
|
||||
>
|
||||
<view class="date-input">
|
||||
<text>{{ endDate || '结束日期' }}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="Card">
|
||||
<text class="Label">页面参数(query)</text>
|
||||
<text class="Mono">{{ params }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-right">
|
||||
<button class="btn-secondary" @click="handleSearch">
|
||||
<text class="iconfont icon-search"></text>
|
||||
查询
|
||||
</button>
|
||||
<button class="btn-primary" @click="handleExport">
|
||||
<text class="iconfont icon-export"></text>
|
||||
导出
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 指标概览 -->
|
||||
<view class="metrics-section">
|
||||
<view class="metrics-row">
|
||||
<view class="metric-card">
|
||||
<view class="metric-icon">
|
||||
<text class="iconfont icon-users"></text>
|
||||
</view>
|
||||
<view class="metric-content">
|
||||
<text class="metric-title">累计用户</text>
|
||||
<text class="metric-value">{{ formatNumber(totalUsers) }}</text>
|
||||
<view class="metric-change up">
|
||||
<text class="iconfont icon-up"></text>
|
||||
<text class="change-text">{{ userGrowth }}%</text>
|
||||
<text class="change-desc">较上月</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="metric-card">
|
||||
<view class="metric-icon">
|
||||
<text class="iconfont icon-eye"></text>
|
||||
</view>
|
||||
<view class="metric-content">
|
||||
<text class="metric-title">访客数</text>
|
||||
<text class="metric-value">{{ formatNumber(totalVisitors) }}</text>
|
||||
<view class="metric-change up">
|
||||
<text class="iconfont icon-up"></text>
|
||||
<text class="change-text">{{ visitorGrowth }}%</text>
|
||||
<text class="change-desc">较上月</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="metric-card">
|
||||
<view class="metric-icon">
|
||||
<text class="iconfont icon-view"></text>
|
||||
</view>
|
||||
<view class="metric-content">
|
||||
<text class="metric-title">浏览量</text>
|
||||
<text class="metric-value">{{ formatNumber(totalPageViews) }}</text>
|
||||
<view class="metric-change down">
|
||||
<text class="iconfont icon-down"></text>
|
||||
<text class="change-text">{{ pageViewDecline }}%</text>
|
||||
<text class="change-desc">较上月</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="metric-card">
|
||||
<view class="metric-icon">
|
||||
<text class="iconfont icon-user-add"></text>
|
||||
</view>
|
||||
<view class="metric-content">
|
||||
<text class="metric-title">新增用户</text>
|
||||
<text class="metric-value">{{ formatNumber(newUsers) }}</text>
|
||||
<view class="metric-change up">
|
||||
<text class="iconfont icon-up"></text>
|
||||
<text class="change-text">{{ newUserGrowth }}%</text>
|
||||
<text class="change-desc">较上月</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="metric-card">
|
||||
<view class="metric-icon">
|
||||
<text class="iconfont icon-shopping"></text>
|
||||
</view>
|
||||
<view class="metric-content">
|
||||
<text class="metric-title">成交用户</text>
|
||||
<text class="metric-value">{{ formatNumber(convertedUsers) }}</text>
|
||||
<view class="metric-change up">
|
||||
<text class="iconfont icon-up"></text>
|
||||
<text class="change-text">{{ conversionGrowth }}%</text>
|
||||
<text class="change-desc">较上月</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="metric-card">
|
||||
<view class="metric-icon">
|
||||
<text class="iconfont icon-vip"></text>
|
||||
</view>
|
||||
<view class="metric-content">
|
||||
<text class="metric-title">付费会员</text>
|
||||
<text class="metric-value">{{ formatNumber(vipUsers) }}</text>
|
||||
<view class="metric-change up">
|
||||
<text class="iconfont icon-up"></text>
|
||||
<text class="change-text">{{ vipGrowth }}%</text>
|
||||
<text class="change-desc">较上月</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户趋势图表 -->
|
||||
<view class="chart-section">
|
||||
<view class="admin-card">
|
||||
<view class="admin-card-header">
|
||||
<text class="admin-card-title">用户数据趋势分析</text>
|
||||
</view>
|
||||
<view class="admin-card-body">
|
||||
<!-- 图表图例 -->
|
||||
<view class="chart-legend">
|
||||
<view class="legend-item" v-for="item in trendLegend" :key="item.key">
|
||||
<view class="legend-color" :style="{ backgroundColor: item.color }"></view>
|
||||
<text class="legend-text">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 多折线图表容器 -->
|
||||
<view class="multi-line-chart">
|
||||
<!-- 图表区域 -->
|
||||
<view class="chart-area">
|
||||
<!-- 模拟多折线图 -->
|
||||
<view class="line-container" v-for="(line, index) in trendLines" :key="line.key">
|
||||
<view class="line-points">
|
||||
<view
|
||||
v-for="(point, pIndex) in line.data"
|
||||
:key="pIndex"
|
||||
class="line-point"
|
||||
:style="{
|
||||
left: (pIndex * 100 / (line.data.length - 1)) + '%',
|
||||
bottom: point.height + '%',
|
||||
backgroundColor: line.color
|
||||
}"
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- X轴标签 -->
|
||||
<view class="x-axis-labels">
|
||||
<text class="axis-label" v-for="date in chartDates" :key="date">{{ date }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import AdminLayout from '@/layouts/admin/index.uvue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
// 筛选条件
|
||||
const selectedChannel = ref(0)
|
||||
const channelOptions = ['全部渠道', '自然流量', '搜索引擎', '社交媒体', '广告投放', '其他']
|
||||
const params = ref('')
|
||||
|
||||
const startDate = ref('')
|
||||
const endDate = ref('')
|
||||
const minDate = '2020-01-01'
|
||||
const maxDate = new Date().toISOString().split('T')[0]
|
||||
|
||||
// 指标数据
|
||||
const totalUsers = ref(32456)
|
||||
const userGrowth = ref(12.5)
|
||||
const totalVisitors = ref(156789)
|
||||
const visitorGrowth = ref(8.3)
|
||||
const totalPageViews = ref(456123)
|
||||
const pageViewDecline = ref(3.2)
|
||||
const newUsers = ref(1234)
|
||||
const newUserGrowth = ref(15.7)
|
||||
const convertedUsers = ref(5678)
|
||||
const conversionGrowth = ref(9.4)
|
||||
const vipUsers = ref(1234)
|
||||
const vipGrowth = ref(22.1)
|
||||
|
||||
// 图表数据
|
||||
const chartDates = ['01-01', '01-08', '01-15', '01-22', '01-29', '02-05', '02-12']
|
||||
|
||||
const trendLegend = [
|
||||
{ key: 'newUsers', name: '新增用户', color: '#1890ff' },
|
||||
{ key: 'visitors', name: '访客数', color: '#52c41a' },
|
||||
{ key: 'pageViews', name: '浏览量', color: '#faad14' },
|
||||
{ key: 'conversions', name: '成交用户', color: '#f5222d' },
|
||||
{ key: 'vipUsers', name: '付费会员', color: '#722ed1' }
|
||||
]
|
||||
|
||||
// 趋势线数据
|
||||
const trendLines = ref([
|
||||
{
|
||||
key: 'newUsers',
|
||||
color: '#1890ff',
|
||||
data: [
|
||||
{ value: 120, height: 12 },
|
||||
{ value: 180, height: 18 },
|
||||
{ value: 250, height: 25 },
|
||||
{ value: 320, height: 32 },
|
||||
{ value: 280, height: 28 },
|
||||
{ value: 350, height: 35 },
|
||||
{ value: 420, height: 42 }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'visitors',
|
||||
color: '#52c41a',
|
||||
data: [
|
||||
{ value: 450, height: 45 },
|
||||
{ value: 520, height: 52 },
|
||||
{ value: 580, height: 58 },
|
||||
{ value: 620, height: 62 },
|
||||
{ value: 550, height: 55 },
|
||||
{ value: 680, height: 68 },
|
||||
{ value: 750, height: 75 }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'pageViews',
|
||||
color: '#faad14',
|
||||
data: [
|
||||
{ value: 680, height: 68 },
|
||||
{ value: 720, height: 72 },
|
||||
{ value: 850, height: 85 },
|
||||
{ value: 920, height: 92 },
|
||||
{ value: 780, height: 78 },
|
||||
{ value: 950, height: 95 },
|
||||
{ value: 1000, height: 100 }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'conversions',
|
||||
color: '#f5222d',
|
||||
data: [
|
||||
{ value: 45, height: 4.5 },
|
||||
{ value: 52, height: 5.2 },
|
||||
{ value: 68, height: 6.8 },
|
||||
{ value: 75, height: 7.5 },
|
||||
{ value: 62, height: 6.2 },
|
||||
{ value: 85, height: 8.5 },
|
||||
{ value: 95, height: 9.5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'vipUsers',
|
||||
color: '#722ed1',
|
||||
data: [
|
||||
{ value: 12, height: 1.2 },
|
||||
{ value: 15, height: 1.5 },
|
||||
{ value: 22, height: 2.2 },
|
||||
{ value: 28, height: 2.8 },
|
||||
{ value: 25, height: 2.5 },
|
||||
{ value: 35, height: 3.5 },
|
||||
{ value: 42, height: 4.2 }
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
// 方法
|
||||
const handleChannelChange = (e: any) => {
|
||||
selectedChannel.value = e.detail.value
|
||||
}
|
||||
|
||||
const handleStartDateChange = (e: any) => {
|
||||
startDate.value = e.detail.value
|
||||
}
|
||||
|
||||
const handleEndDateChange = (e: any) => {
|
||||
endDate.value = e.detail.value
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
uni.showToast({
|
||||
title: '数据已更新',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
const handleExport = () => {
|
||||
uni.showToast({
|
||||
title: '导出功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
const formatNumber = (num: number) => {
|
||||
if (num >= 10000) {
|
||||
return (num / 10000).toFixed(1) + '万'
|
||||
} else if (num >= 1000) {
|
||||
return (num / 1000).toFixed(1) + 'k'
|
||||
}
|
||||
return num.toString()
|
||||
}
|
||||
onLoad((options) => {
|
||||
// options: Record<string, any>
|
||||
params.value = JSON.stringify(options ?? {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ===== 用户统计页面样式 ===== */
|
||||
.user-statistics-page {
|
||||
width: 100%;
|
||||
.Page {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
/* ===== 筛选条件栏 ===== */
|
||||
.filter-section {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
.Header {
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
.Title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.filter-left {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
gap: 32px;
|
||||
flex-wrap: wrap;
|
||||
.SubTitle {
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.filter-right {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
gap: 16px;
|
||||
.Card {
|
||||
margin-top: 24rpx;
|
||||
padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.filter-select {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
background-color: #ffffff;
|
||||
cursor: pointer;
|
||||
min-width: 120px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.date-range {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.date-input {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
background-color: #ffffff;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.date-separator {
|
||||
color: #666666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #1890ff;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #ffffff;
|
||||
color: #666666;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* ===== 指标概览 ===== */
|
||||
|
||||
|
||||
.metrics-row {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
flex: 1;
|
||||
min-width: 280px;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background: linear-gradient(135deg, #1890ff 0%, #36cfc9 100%);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.metric-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.metric-title {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
.Label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.metric-change {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
border-radius: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.metric-change.up {
|
||||
background-color: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.metric-change.down {
|
||||
background-color: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.change-text {
|
||||
margin: 0 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.change-desc {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* ===== 图表区域 ===== */
|
||||
.chart-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.admin-card {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.admin-card-header {
|
||||
padding: 24px 24px 0 24px;
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.admin-card-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.admin-card-body {
|
||||
padding: 0 24px 24px 24px;
|
||||
}
|
||||
|
||||
/* ===== 图表图例 ===== */
|
||||
.chart-legend {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
justify-content: center;
|
||||
gap: 32px;
|
||||
margin-bottom: 24px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
flex-direction:row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.legend-text {
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
/* ===== 多折线图表 ===== */
|
||||
.multi-line-chart {
|
||||
height: 400px;
|
||||
position: relative;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.chart-area {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 60px;
|
||||
right: 40px;
|
||||
bottom: 60px;
|
||||
}
|
||||
|
||||
.line-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.line-points {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.line-point {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #ffffff;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.x-axis-labels {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
|
||||
justify-content: space-between;
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.axis-label {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ===== 响应式设计 ===== */
|
||||
@media (max-width: 1200px) {
|
||||
.metrics-row {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
min-width: 45%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.filter-row {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.filter-left {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.filter-right {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.metrics-row {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
min-width: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-statistics-page {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.filter-section,
|
||||
.chart-section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.admin-card-header,
|
||||
.admin-card-body {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.chart-legend {
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 图标字体 ===== */
|
||||
.iconfont {
|
||||
font-family: 'iconfont';
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-up:before {
|
||||
content: '↑';
|
||||
}
|
||||
|
||||
.icon-down:before {
|
||||
content: '↓';
|
||||
}
|
||||
|
||||
.icon-users:before {
|
||||
content: '👥';
|
||||
}
|
||||
|
||||
.icon-eye:before {
|
||||
content: '👁️';
|
||||
}
|
||||
|
||||
.icon-view:before {
|
||||
content: '📊';
|
||||
}
|
||||
|
||||
.icon-user-add:before {
|
||||
content: '👤';
|
||||
}
|
||||
|
||||
.icon-shopping:before {
|
||||
content: '🛒';
|
||||
}
|
||||
|
||||
.icon-vip:before {
|
||||
content: '👑';
|
||||
}
|
||||
|
||||
.icon-search:before {
|
||||
content: '🔍';
|
||||
}
|
||||
|
||||
.icon-export:before {
|
||||
content: '📤';
|
||||
}
|
||||
|
||||
.icon-down:before {
|
||||
content: '▼';
|
||||
.Mono {
|
||||
font-size: 24rpx;
|
||||
font-family: monospace;
|
||||
line-height: 36rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -466,12 +466,6 @@
|
||||
"navigationBarTitleText": "营销管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "activity-log",
|
||||
"style": {
|
||||
"navigationBarTitleText": "活动日志"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "merchant-review",
|
||||
"style": {
|
||||
@@ -479,7 +473,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "product-review",
|
||||
"path": "product-reviews",
|
||||
"style": {
|
||||
"navigationBarTitleText": "商品审核"
|
||||
}
|
||||
|
||||
1
static/content.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769650806906" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14400" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1024 0H0v1024h1024V0z" fill="#ffffff" fill-opacity=".01" p-id="14401"></path><path d="M149.333333 213.333333a128 128 0 0 1 128-128h554.666667a42.666667 42.666667 0 0 1 42.666667 42.666667v768a42.666667 42.666667 0 0 1-42.666667 42.666667H277.333333a128 128 0 0 1-128-128V213.333333z m128-42.666666a42.666667 42.666667 0 0 0-42.666666 42.666666v597.333334a42.666667 42.666667 0 0 0 42.666666 42.666666h512V170.666667H277.333333z" fill="#ffffff" p-id="14402"></path><path d="M149.333333 789.333333a149.333333 149.333333 0 0 1 149.333334-149.333333h576v256a42.666667 42.666667 0 0 1-42.666667 42.666667H298.666667a149.333333 149.333333 0 0 1-149.333334-149.333334z m149.333334-64a64 64 0 1 0 0 128h490.666666v-128H298.666667z" fill="#ffffff" p-id="14403"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
static/customerService.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769650496978" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7909" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M190.591634 960.526793c-17.717453 0-31.994625-14.277171-31.994625-31.994625 0-69.493701 82.050731-119.721821 226.370569-139.847472l0-9.63279c-97.876029-74.998152-97.876029-213.985554-97.876029-298.616496 0-139.675458 82.222745-223.102301 219.834033-223.102301l7.396607 0c137.611288 0 219.834033 83.426844 219.834033 223.102301 0 10.320847-0.172014 20.641693-0.344028 31.306568-0.516042 17.717453-14.965228 31.650596-32.854695 31.134554-17.717453-0.516042-31.650596-15.137242-31.134554-32.854695 0.344028-9.976818 0.344028-19.781623 0.344028-29.586427 0-105.616664-52.464304-159.113052-155.844784-159.113052l-7.396607 0c-103.38048 0-155.844784 53.496388-155.844784 159.113052 0 102.176382 6.364522 206.244919 83.082815 255.096926 9.288762 5.84848 14.793214 15.997312 14.793214 27.006215L448.956828 817.067025c0 16.341341-12.385016 30.102469-28.554342 31.82261-128.494541 13.589115-197.816227 51.260205-197.816227 79.642533C222.586259 946.077608 208.137074 960.526793 190.591634 960.526793z" fill="#ffffff" p-id="7910"></path><path d="M833.752394 960.526793c-17.717453 0-31.994625-14.277171-31.994625-31.994625 0-28.554342-69.321687-66.053418-197.816227-79.642533-16.341341-1.720141-28.726356-15.48127-28.726356-31.82261l0-54.700487c0-17.717453 14.277171-31.994625 31.994625-31.994625s31.994625 14.277171 31.994625 31.994625l0 26.318159c144.319839 19.953637 226.370569 70.353771 226.370569 139.847472C865.747018 946.077608 851.469847 960.526793 833.752394 960.526793z" fill="#ffffff" p-id="7911"></path><path d="M612.198219 673.435243c-44.035612 0-76.890307-4.472367-77.750378-4.644381-15.825298-4.816395-25.286074-20.813707-21.845792-37.155048 3.268268-16.169326 18.40551-26.834201 34.918864-25.286074 79.814547 8.77272 201.600538 1.204099 222.930287-43.175542 7.568621-15.825298 26.662187-22.705863 42.659499-14.965228 15.997312 7.568621 22.705863 26.834201 14.965228 42.659499C794.705191 660.36217 687.368386 673.435243 612.198219 673.435243z" fill="#ffffff" p-id="7912"></path><path d="M896.021502 639.892491c-17.717453 0-31.994625-14.277171-31.994625-31.994625l0-111.809172-42.831514-15.309256c-12.729044-4.472367-21.32975-16.685369-21.32975-30.102469 0-160.489165-129.182597-291.219889-287.951621-291.219889-158.769024 0-287.951621 130.730724-287.951621 291.219889 0 10.320847-4.988409 19.953637-13.417101 25.974131l-18.577524 13.245087 0 118.00168c0 17.717453-14.277171 31.994625-31.994625 31.994625s-31.994625-14.277171-31.994625-31.994625l0-134.34302c0-10.320847 4.988409-19.953637 13.417101-25.974131l18.921552-13.589115C169.089871 245.980178 323.386528 95.639845 511.913993 95.639845c186.463296 0 339.555854 147.072065 351.252814 332.331262l43.51957 15.48127c12.729044 4.472367 21.32975 16.685369 21.32975 30.102469l0 134.34302C928.016126 625.61532 913.738955 639.892491 896.021502 639.892491z" fill="#ffffff" p-id="7913"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
1
static/design.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769650935205" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16533" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M947.960675 199.328791l-92.764753 92.548836-123.656321-123.434264 92.768847-92.548836c17.024745-17.029862 44.745087-17.029862 61.824067 0l61.828161 61.715597C965.044772 154.637939 965.044772 182.305069 947.960675 199.328791zM298.47437 600.418772l123.656321 123.434264-164.803463 41.091884L298.47437 600.418772zM824.308447 322.766125 453.287295 693.022866 329.634044 569.586556l370.962823-370.256742L824.308447 322.766125zM154.843112 196.272175l0 673.501254 673.503301 0L828.346413 383.884111l87.855954-87.853907L916.202367 913.702941c0 24.287149-19.641339 43.930535-43.927465 43.930535L110.91667 957.633477c-24.282033 0-43.927465-19.642362-43.927465-43.930535L66.989205 152.34471c0-24.281009 19.645432-43.926442 43.927465-43.926442l620.184955 0-87.85493 87.853907L154.843112 196.272175z" p-id="16534" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
static/maintain.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769651728600" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17765" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M870.4 1017.6c-32 0-70.4-12.8-89.6-38.4l-192-192h-6.4c-25.6 6.4-51.2 12.8-76.8 12.8-19.2 0-38.4 0-57.6-6.4-51.2-12.8-96-38.4-134.4-76.8-64-64-96-160-76.8-256 6.4-25.6 25.6-44.8 44.8-51.2h19.2c19.2 0 32 6.4 44.8 19.2l64 64c6.4 12.8 19.2 19.2 32 19.2s25.6-6.4 32-12.8c19.2-19.2 19.2-51.2 0-70.4l-70.4-64c-12.8-19.2-19.2-44.8-12.8-70.4 6.4-25.6 25.6-38.4 51.2-44.8 19.2-6.4 38.4-6.4 57.6-6.4 76.8 0 147.2 32 198.4 83.2 38.4 38.4 64 83.2 76.8 134.4 12.8 44.8 6.4 96-6.4 134.4v6.4l192 192c25.6 25.6 38.4 57.6 38.4 89.6 0 32-12.8 70.4-38.4 89.6-25.6 32-57.6 44.8-89.6 44.8zM588.8 704c19.2 0 38.4 6.4 44.8 19.2l198.4 198.4c6.4 6.4 19.2 12.8 32 12.8s25.6-6.4 32-12.8c6.4-6.4 12.8-19.2 12.8-32s-6.4-25.6-12.8-32l-192-198.4c-19.2-19.2-25.6-44.8-19.2-70.4 12.8-32 12.8-70.4 6.4-108.8-6.4-38.4-25.6-70.4-51.2-96-38.4-38.4-83.2-57.6-128-57.6h-25.6l51.2 51.2c25.6 25.6 38.4 57.6 38.4 89.6 0 32-12.8 70.4-38.4 89.6-25.6 25.6-64 38.4-96 38.4s-70.4-12.8-89.6-38.4l-51.2-51.2v25.6c0 51.2 25.6 96 57.6 128 25.6 25.6 64 44.8 96 57.6 12.8 0 25.6 6.4 44.8 6.4 19.2 0 44.8-6.4 64-12.8 6.4-6.4 12.8-6.4 25.6-6.4z" p-id="17766" fill="#ffffff"></path><path d="M198.4 1017.6c-51.2 0-160-32-160-140.8V192c0-128 83.2-192 160-192h556.8c96 0 160 64 160 166.4v230.4c0 19.2-12.8 44.8-38.4 44.8-32-6.4-44.8-19.2-44.8-38.4V185.6c0-70.4-64-96-89.6-96H198.4c-32 0-83.2 38.4-83.2 121.6v640c0 96 64 96 89.6 96h192c25.6-6.4 38.4 19.2 38.4 38.4s-12.8 38.4-44.8 38.4h-192z" p-id="17767" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
1
static/marketing.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769650307704" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6851" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M249.508859 1024H94.442596a20.861467 20.861467 0 0 1-20.861467-20.861467V540.908033a20.861467 20.861467 0 0 1 20.861467-20.861467h155.066263a20.861467 20.861467 0 0 1 20.861467 20.861467V1003.138533a20.861467 20.861467 0 0 1-20.861467 20.861467zM115.304063 982.277066h113.343329V561.769499H115.304063zM600.982852 1024h-185.965075a20.861467 20.861467 0 0 1-20.861467-20.861467V457.736345a20.861467 20.861467 0 0 1 20.861467-20.861467h185.965075a20.861467 20.861467 0 0 1 20.861467 20.861467V1003.138533a20.861467 20.861467 0 0 1-20.861467 20.861467z m-165.12745-41.722934h144.242142V478.597811h-144.242142zM941.501595 1023.976158H746.524366a20.861467 20.861467 0 0 1-20.861467-20.861466V367.066449a20.861467 20.861467 0 0 1 20.861467-20.861466h194.977229a20.861467 20.861467 0 0 1 20.861467 20.861466v636.048243a20.861467 20.861467 0 0 1-20.861467 20.861466z m-174.127683-41.722933h153.266216V387.915995H767.385832zM661.755285 329.742305a20.801863 20.801863 0 0 1-13.51823-4.98291L355.258615 75.23241 65.379593 298.831572a20.861467 20.861467 0 0 1-29.265658-3.778906 20.861467 20.861467 0 0 1 3.826589-29.313341l303.266123-233.922608a20.861467 20.861467 0 0 1 26.225844 0.631805l291.714832 248.501792L914.40553 45.37071l-141.428824 8.940629A20.861467 20.861467 0 0 1 750.839709 34.808847a20.861467 20.861467 0 0 1 19.502491-22.136996L970.052002 0.059604a20.873388 20.873388 0 0 1 20.48 12.576484 20.861467 20.861467 0 0 1-4.959068 23.519814L675.976845 324.151432a20.825704 20.825704 0 0 1-14.22156 5.590873z" p-id="6852" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769417734574" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="27067" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M800.037628 928.016126 223.962372 928.016126c-52.980346 0-95.983874-43.003528-95.983874-95.983874l0-639.892491c0-52.980346 43.003528-95.983874 95.983874-95.983874l575.903242 0c52.980346 0 95.983874 43.003528 95.983874 95.983874l0 639.892491C896.021502 884.840585 852.84596 928.016126 800.037628 928.016126zM223.962372 159.973123c-17.545439 0-31.994625 14.449185-31.994625 31.994625l0 639.892491c0 17.717453 14.449185 31.994625 31.994625 31.994625l575.903242 0c17.717453 0 31.994625-14.277171 31.994625-31.994625l0-639.892491c0-17.545439-14.277171-31.994625-31.994625-31.994625L223.962372 159.973123z" fill="#ffffff" p-id="27068"></path><path d="M640.924576 544.768688 287.779607 544.768688c-17.717453 0-31.994625-14.277171-31.994625-31.994625 0-17.717453 14.277171-31.994625 31.994625-31.994625l353.144969 0c17.717453 0 31.994625 14.277171 31.994625 31.994625C672.9192 530.491517 658.642029 544.768688 640.924576 544.768688z" fill="#ffffff" p-id="27069"></path><path d="M734.84428 735.532337l-447.236687 0c-17.717453 0-31.994625-14.277171-31.994625-31.994625s14.277171-31.994625 31.994625-31.994625l447.236687 0c17.717453 0 31.994625 14.277171 31.994625 31.994625S752.561734 735.532337 734.84428 735.532337z" fill="#ffffff" p-id="27070"></path><path d="M255.784982 305.325046c0 26.490173 21.501764 47.991937 47.991937 47.991937s47.991937-21.501764 47.991937-47.991937-21.501764-47.991937-47.991937-47.991937S255.784982 278.834873 255.784982 305.325046z" fill="#ffffff" p-id="27071"></path><path d="M463.061986 305.325046c0 26.490173 21.501764 47.991937 47.991937 47.991937s47.991937-21.501764 47.991937-47.991937-21.501764-47.991937-47.991937-47.991937S463.061986 278.834873 463.061986 305.325046z" fill="#ffffff" p-id="27072"></path><path d="M671.199059 305.325046c0 26.490173 21.501764 47.991937 47.991937 47.991937s47.991937-21.501764 47.991937-47.991937-21.501764-47.991937-47.991937-47.991937S671.199059 278.834873 671.199059 305.325046z" fill="#ffffff" p-id="27073"></path></svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769650833109" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15467" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M341.8624 153.6C346.0608 119.9232 374.784 93.866667 409.6 93.866667h204.8c34.816 0 63.5392 26.056533 67.7376 59.733333H827.733333c37.704533 0 68.266667 30.562133 68.266667 68.266667v640c0 37.704533-30.562133 68.266667-68.266667 68.266666H196.266667c-37.704533 0-68.266667-30.562133-68.266667-68.266666V221.866667c0-37.704533 30.562133-68.266667 68.266667-68.266667h145.595733z m0 51.2H196.266667a17.066667 17.066667 0 0 0-17.066667 17.066667v640a17.066667 17.066667 0 0 0 17.066667 17.066666h631.466666a17.066667 17.066667 0 0 0 17.066667-17.066666V221.866667a17.066667 17.066667 0 0 0-17.066667-17.066667h-145.595733c-4.1984 33.6768-32.925867 59.733333-67.7376 59.733333H409.6c-34.816 0-63.5392-26.056533-67.7376-59.733333zM409.6 145.066667a17.066667 17.066667 0 0 0-17.066667 17.066666v34.133334a17.066667 17.066667 0 0 0 17.066667 17.066666h204.8a17.066667 17.066667 0 0 0 17.066667-17.066666v-34.133334a17.066667 17.066667 0 0 0-17.066667-17.066666H409.6z m52.8896 463.095466l186.794667-186.794666a25.6 25.6 0 1 1 36.206933 36.202666l-201.847467 201.8432a25.770667 25.770667 0 0 1-2.794666 3.310934 25.514667 25.514667 0 0 1-8.546134 5.653333 24.9472 24.9472 0 0 1-28.16-5.661867 26.5088 26.5088 0 0 1-2.3424-2.833066l-105.770666-105.770667a25.6 25.6 0 1 1 36.202666-36.202667l90.257067 90.2528z" fill="#ffffff" p-id="15468"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.6 KiB |
1
static/product.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769650653750" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9834" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M925.6 845.9l-80.3-499.5c-5.3-32.9-33.3-56.7-66.6-56.7h-76.2c-4.9-46.5-23.2-89.8-52.6-123.8-36.2-41.8-84.9-64.8-137-64.8-52.1 0-100.7 23-137 64.8-29.5 34-47.7 77.2-52.6 123.8h-76.2c-33.3 0-61.3 23.9-66.6 56.7l-80.3 499.5c-3.1 19.5 2.4 39.4 15.3 54.4 12.8 15.1 31.5 23.7 51.3 23.7H859c19.8 0 38.5-8.6 51.3-23.7 12.9-15 18.4-34.9 15.3-54.4zM512.9 181.1c53.9 0 99 46.8 108.9 108.6H404c9.9-61.8 55-108.6 108.9-108.6zM181.6 844l76.2-474.3H768L844.3 844H181.6z" p-id="9835" fill="#ffffff"></path><path d="M632.4 656.3c-30.9 18.7-74.4 29.4-119.5 29.4-45.1 0-88.6-10.7-119.5-29.4-24.7-14.9-39-33.5-39-50.8l-80 0.4c0.1 24.2 8.1 48.2 23 69.5 13.2 18.9 31.6 35.5 54.6 49.4 43.6 26.4 100.8 40.9 160.9 40.9 60.1 0 117.2-14.5 160.9-40.9 23-13.9 41.4-30.5 54.6-49.4 14.9-21.3 22.9-45.3 23-69.5l-80-0.4c0 17.3-14.3 35.8-39 50.8z" p-id="9836" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769417326653" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23918" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M800.037628 928.016126 223.962372 928.016126c-52.980346 0-95.983874-43.003528-95.983874-95.983874l0-639.892491c0-52.980346 43.003528-95.983874 95.983874-95.983874l575.903242 0c52.980346 0 95.983874 43.003528 95.983874 95.983874l0 639.892491C896.021502 884.840585 852.84596 928.016126 800.037628 928.016126zM223.962372 159.973123c-17.545439 0-31.994625 14.449185-31.994625 31.994625l0 639.892491c0 17.717453 14.449185 31.994625 31.994625 31.994625l575.903242 0c17.717453 0 31.994625-14.277171 31.994625-31.994625l0-639.892491c0-17.545439-14.277171-31.994625-31.994625-31.994625L223.962372 159.973123z" fill="#ffffff" p-id="23919"></path><path d="M640.924576 544.768688 287.779607 544.768688c-17.717453 0-31.994625-14.277171-31.994625-31.994625 0-17.717453 14.277171-31.994625 31.994625-31.994625l353.144969 0c17.717453 0 31.994625 14.277171 31.994625 31.994625C672.9192 530.491517 658.642029 544.768688 640.924576 544.768688z" fill="#ffffff" p-id="23920"></path><path d="M734.84428 735.532337l-447.236687 0c-17.717453 0-31.994625-14.277171-31.994625-31.994625s14.277171-31.994625 31.994625-31.994625l447.236687 0c17.717453 0 31.994625 14.277171 31.994625 31.994625S752.561734 735.532337 734.84428 735.532337z" fill="#ffffff" p-id="23921"></path><path d="M255.784982 305.325046c0 26.490173 21.501764 47.991937 47.991937 47.991937s47.991937-21.501764 47.991937-47.991937-21.501764-47.991937-47.991937-47.991937S255.784982 278.834873 255.784982 305.325046z" fill="#ffffff" p-id="23922"></path><path d="M463.061986 305.325046c0 26.490173 21.501764 47.991937 47.991937 47.991937s47.991937-21.501764 47.991937-47.991937-21.501764-47.991937-47.991937-47.991937S463.061986 278.834873 463.061986 305.325046z" fill="#ffffff" p-id="23923"></path><path d="M671.199059 305.325046c0 26.490173 21.501764 47.991937 47.991937 47.991937s47.991937-21.501764 47.991937-47.991937-21.501764-47.991937-47.991937-47.991937S671.199059 278.834873 671.199059 305.325046z" fill="#ffffff" p-id="23924"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1769417346887" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="24969" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M992 672h-24c-4.4 0-8-3.6-8-8V136c0-4.4 3.6-8 8-8h24c17.7 0 32-14.3 32-32s-14.3-32-32-32H580c-2.2 0-4-1.8-4-4 0-16.6-6.7-31.6-17.6-42.4C547.6 6.7 532.6 0 516 0h-8c-33.1 0-60 26.9-60 60 0 1.1-0.4 2.1-1.2 2.8-0.7 0.7-1.7 1.2-2.8 1.2H32C14.3 64 0 78.3 0 96c0 8.8 3.6 16.8 9.4 22.6 5.8 5.8 13.8 9.4 22.6 9.4h24c4.4 0 8 3.6 8 8v528c0 4.4-3.6 8-8 8H32c-17.7 0-32 14.3-32 32 0 8.8 3.6 16.8 9.4 22.6 5.8 5.8 13.8 9.4 22.6 9.4h364.1c10.2 0 17.8 9.5 15.6 19.5L360.4 986c-4.3 19.5 10.5 38 30.5 38 7.3 0 14.2-2.5 19.6-6.9 5.4-4.3 9.4-10.5 10.9-17.6l50.7-228c1-4.7 7.9-3.9 7.9 0.9v220.3c0 17.3 14 31.2 31.2 31.2h1.5c17.3 0 31.2-14 31.2-31.2V772.4c0-4.8 6.9-5.5 7.9-0.9l50.7 228c3.2 14.3 15.8 24.4 30.5 24.5h0.1c20 0 34.9-18.5 30.5-38l-51.3-230.5c-2.2-10 5.4-19.5 15.6-19.5H992c17.7 0 32-14.3 32-32 0-8.8-3.6-16.8-9.4-22.6-5.8-5.8-13.8-9.4-22.6-9.4z m-704-68V420c0-2.2 1.8-4 4-4h56c2.2 0 4 1.8 4 4v184c0 2.2-1.8 4-4 4h-56c-2.2 0-4-1.8-4-4z m128 0V388c0-2.2 1.8-4 4-4h56c2.2 0 4 1.8 4 4v216c0 2.2-1.8 4-4 4h-56c-2.2 0-4-1.8-4-4z m128 0V324c0-2.2 1.8-4 4-4h56c2.2 0 4 1.8 4 4v280c0 2.2-1.8 4-4 4h-56c-2.2 0-4-1.8-4-4z m192 0c0 2.2-1.8 4-4 4h-56c-2.2 0-4-1.8-4-4V228c0-2.2 1.8-4 4-4h56c2.2 0 4 1.8 4 4v376z" p-id="24970" fill="#ffffff"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |