补充页面内容

This commit is contained in:
2026-02-11 19:51:32 +08:00
parent 50ddf01e7c
commit 53820a4654
30 changed files with 5915 additions and 259 deletions

View File

@@ -1,21 +1,330 @@
<template>
<AdminLayout currentPage="dev-tools-api">
<view class="page">
<view class="header">
<text class="title">接口管理</text>
</view>
<view class="content">
<text class="tip">TODO: 接口管理</text>
</view>
</view>
</AdminLayout>
</template>
<script setup lang="uts">
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
</script>
<style scoped>
.page { padding: 16px; }
.title { font-size: 18px; font-weight: 600; }
.tip { color: #999; margin-top: 8px; display: block; }
<view class="admin-page api-management">
<!-- 左侧分类树 -->
<view class="sidebar-tree">
<view class="sidebar-header">
<button class="btn-primary-sm">新增分类</button>
<button class="btn-success-sm ml-10">同步</button>
</view>
<scroll-view class="tree-scroll" scroll-y="true">
<view class="tree-node" v-for="(group, gIndex) in apiGroups" :key="gIndex">
<view class="node-label">
<text class="arrow">▼</text>
<text class="folder-icon">📁</text>
<text class="label-text">{{ group.name }}</text>
</view>
<view class="node-children">
<view
class="child-item"
v-for="(api, aIndex) in group.children"
:key="aIndex"
:class="{ active: selectedApiId === api.id }"
@click="selectedApiId = api.id"
>
<text class="method-tag" :class="api.method.toLowerCase()">{{ api.method }}</text>
<text class="api-name">{{ api.name }}</text>
<text class="more-icon">...</text>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 右侧接口详情 -->
<view class="api-content">
<view class="content-header">
<text class="current-api-title">分销员列表</text>
<view class="header-actions">
<button class="btn-secondary-sm">调试</button>
<button class="btn-primary-sm ml-10">编辑</button>
</view>
</view>
<view class="info-section">
<view class="info-title">接口信息</view>
<view class="info-list">
<view class="info-item">
<text class="info-label">接口名称:</text>
<text class="info-value">分销员列表</text>
</view>
<view class="info-item">
<text class="info-label">请求类型:</text>
<text class="method-badge get">GET</text>
</view>
<view class="info-item">
<text class="info-label">功能描述:</text>
<text class="info-value">--</text>
</view>
<view class="info-item">
<text class="info-label">是否公共:</text>
<text class="info-value">否</text>
</view>
</view>
</view>
<view class="info-section">
<view class="info-title">调用方式</view>
<view class="info-list">
<view class="info-item">
<text class="info-label">路由地址:</text>
<text class="info-value">agent/index</text>
</view>
<view class="info-item">
<text class="info-label">文件地址:</text>
<text class="info-value">app/adminapi/controller/v1/agent/AgentManage.php</text>
</view>
<view class="info-item">
<text class="info-label">方法名:</text>
<text class="info-value">index</text>
</view>
</view>
</view>
<!-- 参数表格 -->
<view class="params-section">
<view class="info-title">header参数</view>
<view class="params-table">
<view class="table-head">
<view class="th p-attr">属性</view>
<view class="th p-type">类型</view>
<view class="th p-required">必须</view>
<view class="th p-desc">说明</view>
</view>
<view class="table-row">
<view class="td p-attr">Authori-zation</view>
<view class="td p-type">string</view>
<view class="td p-required">否</view>
<view class="td p-desc">--</view>
</view>
</view>
</view>
<view class="params-section mt-20">
<view class="info-title">query参数</view>
<view class="params-table">
<view class="table-head">
<view class="th p-attr">属性</view>
<view class="th p-type">类型</view>
<view class="th p-required">必须</view>
<view class="th p-desc">说明</view>
</view>
<view class="table-row" v-for="(p, i) in queryParams" :key="i">
<view class="td p-attr">{{ p.attr }}</view>
<view class="td p-type">{{ p.type }}</view>
<view class="td p-required">{{ p.required }}</view>
<view class="td p-desc">{{ p.desc }}</view>
</view>
</view>
</view>
</view>
</view></template>
<script setup lang="uts">
import { ref } from 'vue'
const selectedApiId = ref('1-1')
const apiGroups = ref([
{
name: '分销员管理',
children: [
{ id: '1-1', name: '分销员列表', method: 'GET' },
{ id: '1-2', name: '修改上级推广人', method: 'PUT' },
{ id: '1-3', name: '分销员列表头部统计', method: 'GET' },
{ id: '1-4', name: '推广人列表', method: 'GET' },
{ id: '1-5', name: '推广订单列表', method: 'GET' }
]
},
{
name: '分销设置',
children: []
},
{
name: '分销等级',
children: []
}
])
const queryParams = ref([
{ attr: 'page', type: 'string', required: '是', desc: '页码' },
{ attr: 'limit', type: 'string', required: '是', desc: '每页条数' },
{ attr: 'nickname', type: 'string', required: '是', desc: '用户昵称/用户id/手机号码' }
])
</script>
<style scoped>
.api-management {
display: flex;
flex-direction: row;
height: calc(100vh - 64px);
background-color: #fff;
}
.sidebar-tree {
width: 260px;
border-right: 1px solid #f0f0f0;
display: flex;
flex-direction: column;
}
.sidebar-header {
padding: 15px;
border-bottom: 1px solid #f0f0f0;
display: flex;
flex-direction: row;
}
.tree-scroll {
flex: 1;
}
.tree-node {
padding: 5px 0;
}
.node-label {
padding: 8px 15px;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
}
.label-text {
font-size: 14px;
font-weight: 500;
margin-left: 5px;
}
.node-children {
padding-left: 20px;
}
.child-item {
padding: 8px 15px;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
position: relative;
}
.child-item.active {
background-color: #e6f7ff;
color: #1890ff;
}
.method-tag {
font-size: 10px;
padding: 0 4px;
border-radius: 2px;
margin-right: 8px;
min-width: 30px;
text-align: center;
}
.method-tag.get { color: #52c41a; border: 1px solid #b7eb8f; background: #f6ffed; }
.method-tag.put { color: #faad14; border: 1px solid #ffe58f; background: #fffbe6; }
.api-name {
font-size: 13px;
flex: 1;
}
.api-content {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.content-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
}
.current-api-title {
font-size: 20px;
font-weight: 500;
}
.info-section {
margin-bottom: 30px;
}
.info-title {
font-size: 16px;
font-weight: 500;
margin-bottom: 15px;
}
.info-list {
display: flex;
flex-direction: column;
gap: 12px;
padding-left: 15px;
}
.info-item {
display: flex;
flex-direction: row;
align-items: center;
}
.info-label {
font-size: 14px;
color: #666;
width: 80px;
}
.info-value {
font-size: 14px;
color: #333;
}
.method-badge {
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
}
.method-badge.get { background-color: #e6f7ff; color: #1890ff; }
.params-table {
border: 1px solid #f0f0f0;
border-radius: 4px;
}
.table-head {
background-color: #f8f8f9;
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
}
.th, .td {
padding: 12px;
font-size: 13px;
}
.p-attr { flex: 2; }
.p-type { flex: 1; }
.p-required { flex: 1; }
.p-desc { flex: 3; }
.btn-primary-sm { background-color: #1890ff; color: #fff; font-size: 12px; padding: 5px 10px; border-radius: 4px; border: none; }
.btn-success-sm { background-color: #52c41a; color: #fff; font-size: 12px; padding: 5px 10px; border-radius: 4px; border: none; }
.btn-secondary-sm { background-color: #fff; color: #666; border: 1px solid #d9d9d9; font-size: 12px; padding: 5px 10px; border-radius: 4px; }
.ml-10 { margin-left: 10px; }
.mt-20 { margin-top: 20px; }
</style>

View File

@@ -1,7 +1,6 @@
<template>
<AdminLayout currentPage="dev-tools-codegen">
<view class="admin-page">
<view class="page">
<view class="header">
<text class="title">代码生成</text>
</view>
@@ -9,5 +8,14 @@
<text class="tip">TODO: 代码生成</text>
</view>
</view>
</AdminLayout>
</template>
</view>
</template>
<script setup lang="uts">
</script>
<style scoped>
.admin-page {
padding: 20px;
}
</style>

View File

@@ -1,12 +1,200 @@
<template>
<AdminLayout currentPage="dev-tools-dict">
<view class="page">
<view class="header">
<text class="title">数据字典</text>
</view>
<view class="content">
<text class="tip">TODO: 数据字典</text>
</view>
</view>
</AdminLayout>
</template>
<view class="admin-page data-dictionary">
<view class="admin-sections">
<view class="admin-card">
<!-- 搜索和添加 -->
<view class="header-tools">
<view class="search-form">
<text class="label">字典名称:</text>
<input class="search-input" v-model="searchQuery" placeholder="请输入字典名称" />
<button class="btn-search" @click="handleSearch">查询</button>
</view>
<button class="btn-primary" @click="handleAdd">添加数据字典</button>
</view>
<!-- 数据表格 -->
<view class="table-container">
<view class="table-header">
<view class="table-cell" style="flex: 0 0 60px;">ID</view>
<view class="table-cell" style="flex: 2;">字典名称</view>
<view class="table-cell" style="flex: 2;">数据标识</view>
<view class="table-cell" style="flex: 1;">类型</view>
<view class="table-cell" style="flex: 2;">添加时间</view>
<view class="table-cell action-cell" style="flex: 2;">操作</view>
</view>
<view class="table-body">
<view class="table-row" v-for="(item, index) in dictionaryList" :key="index">
<view class="table-cell" style="flex: 0 0 60px;">{{ item.id }}</view>
<view class="table-cell" style="flex: 2;">{{ item.name }}</view>
<view class="table-cell" style="flex: 2;">{{ item.tag }}</view>
<view class="table-cell" style="flex: 1;">{{ item.type }}</view>
<view class="table-cell" style="flex: 2;">{{ item.add_time }}</view>
<view class="table-cell action-cell" style="flex: 2;">
<text class="action-link" @click="handleEdit(item)">编辑</text>
<text class="action-link ml-10" @click="handleManage(item)">数据管理</text>
<text class="action-link link-danger ml-10" @click="handleDelete(item)">删除</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view></template>
<script setup lang="uts">
import { ref } from 'vue'
const searchQuery = ref('')
const dictionaryList = ref([
{ id: 8, name: '21', tag: '25425', type: '一级', add_time: '2024-08-23 17:37:08' },
{ id: 10, name: '相册', tag: 'xc', type: '多级', add_time: '2024-09-09 15:49:58' },
{ id: 11, name: '品类', tag: 'category', type: '多级', add_time: '2024-09-24 17:47:16' },
{ id: 12, name: '123', tag: '1', type: '一级', add_time: '2024-09-27 15:57:03' },
{ id: 13, name: '企业类型', tag: 'company_type', type: '多级', add_time: '2024-09-27 16:16:21' },
{ id: 14, name: '测试', tag: '343322222222234555343434', type: '多级', add_time: '2024-09-27 16:17:23' },
{ id: 16, name: '用户管理模块', tag: '123', type: '多级', add_time: '2024-10-22 09:30:46' },
{ id: 18, name: '类型', tag: '1', type: '多级', add_time: '2024-12-11 13:48:01' },
{ id: 19, name: '店铺', tag: 'shop', type: '多级', add_time: '2024-12-11 22:23:07' },
{ id: 20, name: 'ce', tag: 'zzz', type: '一级', add_time: '2024-12-14 12:19:17' }
])
function handleSearch() {
uni.showToast({ title: '搜索: ' + searchQuery.value, icon: 'none' })
}
function handleAdd() {
uni.showToast({ title: '添加数据字典', icon: 'none' })
}
function handleEdit(item: any) {
uni.showToast({ title: '编辑: ' + item.name, icon: 'none' })
}
function handleManage(item: any) {
uni.showToast({ title: '数据管理: ' + item.name, icon: 'none' })
}
function handleDelete(item: any) {
uni.showModal({
title: '提示',
content: '确定删除该数据字典吗?',
success: (res) => {
if (res.confirm) {
uni.showToast({ title: '已删除', icon: 'success' })
}
}
})
}
</script>
<style scoped>
.admin-page {
padding: 20px;
background-color: #f5f7f9;
min-height: 100vh;
}
.admin-card {
background-color: #fff;
padding: 24px;
border-radius: 8px;
}
.header-tools {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.search-form {
display: flex;
flex-direction: row;
align-items: center;
}
.label {
font-size: 14px;
color: #333;
margin-right: 10px;
}
.search-input {
width: 200px;
height: 32px;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 0 12px;
font-size: 14px;
margin-right: 10px;
}
.btn-search {
background-color: #1890ff;
color: #fff;
font-size: 14px;
height: 32px;
line-height: 32px;
padding: 0 15px;
border-radius: 4px;
border: none;
}
.btn-primary {
background-color: #1890ff;
color: #fff;
font-size: 14px;
height: 32px;
line-height: 32px;
padding: 0 20px;
border-radius: 4px;
border: none;
}
.table-container {
border: 1px solid #f0f0f0;
border-radius: 4px;
}
.table-header {
display: flex;
flex-direction: row;
background-color: #f8f8f9;
border-bottom: 1px solid #f0f0f0;
padding: 12px 10px;
}
.table-body {
display: flex;
flex-direction: column;
}
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #f0f0f0;
padding: 12px 10px;
align-items: center;
}
.table-cell {
font-size: 14px;
color: #666;
padding: 0 10px;
}
.action-link {
color: #1890ff;
font-size: 13px;
cursor: pointer;
}
.link-danger {
color: #ff4d4f;
}
.ml-10 {
margin-left: 10px;
}
</style>

View File

@@ -1,12 +1,146 @@
<template>
<AdminLayout currentPage="dev-tools-db">
<view class="page">
<view class="header">
<text class="title">数据库管理</text>
</view>
<view class="content">
<text class="tip">TODO: 数据库管理</text>
</view>
</view>
</AdminLayout>
<view class="admin-page">
<view class="admin-sections">
<view class="admin-card">
<view class="page-header">
<text class="page-title">数据库管理</text>
<view class="header-btns">
<button class="btn btn-primary btn-sm" @click="handleExport">备份数据库</button>
</view>
</view>
<!-- 数据表格 -->
<view class="admin-table">
<view class="thead">
<view class="th col-name">表名</view>
<view class="th col-engine">引擎</view>
<view class="th col-rows">行数</view>
<view class="th col-size">数据大小</view>
<view class="th col-index">索引大小</view>
<view class="th col-comment">备注</view>
<view class="th col-op">操作</view>
</view>
<view class="tbody">
<view v-for="(item, index) in tableData" :key="index" class="tr">
<view class="td col-name">{{ item.name }}</view>
<view class="td col-engine">{{ item.engine }}</view>
<view class="td col-rows">{{ item.rows }}</view>
<view class="td col-size">{{ item.dataSize }}</view>
<view class="td col-index">{{ item.indexSize }}</view>
<view class="td col-comment">{{ item.comment }}</view>
<view class="td col-op">
<text class="op-link" @click="handleOptimize(item.name)">优化</text>
<text class="op-link" @click="handleRepair(item.name)">修复</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
const tableData = ref([
{ name: 'eb_system_admin', engine: 'InnoDB', rows: 5, dataSize: '16.00 KB', indexSize: '16.00 KB', comment: '后台管理员表' },
{ name: 'eb_user', engine: 'InnoDB', rows: 1250, dataSize: '320.00 KB', indexSize: '156.00 KB', comment: '用户表' },
{ name: 'eb_store_product', engine: 'InnoDB', rows: 86, dataSize: '1.20 MB', indexSize: '64.00 KB', comment: '商品表' },
{ name: 'eb_store_order', engine: 'InnoDB', rows: 4521, dataSize: '2.50 MB', indexSize: '512.00 KB', comment: '订单表' },
{ name: 'eb_system_config', engine: 'InnoDB', rows: 156, dataSize: '48.00 KB', indexSize: '16.00 KB', comment: '系统配置表' }
])
function handleExport() {
uni.showLoading({ title: '正在备份...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '备份成功' })
}, 1500)
}
function handleOptimize(name: string) {
uni.showToast({ title: '优化表: ' + name, icon: 'none' })
}
function handleRepair(name: string) {
uni.showToast({ title: '修复表: ' + name, icon: 'none' })
}
</script>
<style scoped>
.admin-page {
padding: 20px;
}
.admin-card {
background-color: #fff;
padding: 20px;
border-radius: 4px;
}
.page-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.page-title {
font-size: 16px;
font-weight: bold;
}
.btn-sm {
height: 32px;
line-height: 32px;
font-size: 14px;
padding: 0 15px;
}
.btn-primary {
background-color: #1890ff;
color: #fff;
}
/* 表格样式 */
.admin-table {
border: 1px solid #e8eaec;
}
.thead {
display: flex;
flex-direction: row;
background-color: #f8f8f9;
border-bottom: 1px solid #e8eaec;
}
.tbody {
display: flex;
flex-direction: column;
}
.tr {
display: flex;
flex-direction: row;
border-bottom: 1px solid #e8eaec;
}
.tr:last-child {
border-bottom: none;
}
.th, .td {
padding: 12px 10px;
font-size: 14px;
color: #515a6e;
display: flex;
align-items: center;
}
.th {
font-weight: bold;
}
.col-name { flex: 2; }
.col-engine { flex: 1; }
.col-rows { flex: 1; }
.col-size { flex: 1; }
.col-index { flex: 1; }
.col-comment { flex: 2; }
.col-op { width: 120px; justify-content: space-around; }
.op-link {
color: #1890ff;
cursor: pointer;
}
</style>

View File

@@ -1,12 +1,144 @@
<template>
<AdminLayout currentPage="dev-tools-file">
<view class="page">
<view class="header">
<text class="title">文件管理</text>
</view>
<view class="content">
<text class="tip">TODO: 文件管理</text>
</view>
</view>
</AdminLayout>
<view class="admin-page file-login-container">
<view class="login-card">
<view class="login-header">
<text class="login-title">文件管理登录</text>
</view>
<view class="login-form">
<view class="form-item">
<input
class="login-input"
type="password"
v-model="password"
placeholder="请输入密码"
/>
</view>
<view class="form-tip">
提示:密码配置在 /config/filesystem.php 文件中修改 'password' => '密码'
</view>
<button class="login-btn" @click="handleLogin">登录</button>
</view>
</view>
<!-- 底部备案/版本信息 (1:1 复刻 CRMEB) -->
<view class="login-footer">
<view class="footer-links">
<text class="footer-link">官网</text>
<text class="footer-link">社区</text>
<text class="footer-link">文档</text>
</view>
<view class="copyright">
Copyright © 2014-2025 CRMEB-BZ v5.6.4
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
const password = ref('')
const handleLogin = () => {
if (!password.value) {
uni.showToast({ title: '请输入密码', icon: 'none' })
return
}
uni.showLoading({ title: '正在登录...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '登录成功(演示)' })
}, 1000)
}
</script>
<style scoped>
.admin-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: calc(100vh - 120px);
background-color: #f5f7f9;
}
.login-card {
width: 400px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
padding: 40px;
}
.login-header {
text-align: center;
margin-bottom: 30px;
}
.login-title {
font-size: 28px;
color: #1890ff;
font-weight: 500;
}
.login-form {
display: flex;
flex-direction: column;
}
.form-item {
margin-bottom: 20px;
}
.login-input {
width: 100%;
height: 40px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 15px;
font-size: 14px;
box-sizing: border-box;
}
.form-tip {
font-size: 12px;
color: #909399;
margin-bottom: 20px;
text-align: center;
}
.login-btn {
width: 120px;
height: 40px;
line-height: 40px;
background-color: #1890ff;
color: #fff;
font-size: 14px;
align-self: center;
border-radius: 4px;
border: none;
}
.login-footer {
margin-top: 50px;
text-align: center;
}
.footer-links {
display: flex;
flex-direction: row;
justify-content: center;
gap: 20px;
margin-bottom: 10px;
}
.footer-link {
font-size: 14px;
color: #606266;
}
.copyright {
font-size: 14px;
color: #909399;
}
</style>