1
This commit is contained in:
14
demo/.babelrc
Normal file
14
demo/.babelrc
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"modules": false,
|
||||
"targets": {
|
||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
24
demo/.gitignore
vendored
Normal file
24
demo/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# 依赖
|
||||
node_modules/
|
||||
|
||||
# 构建输出
|
||||
dist/
|
||||
|
||||
# 日志
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# 编辑器
|
||||
.vscode/
|
||||
.idea/
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# 系统文件
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
351
demo/README-LOCAL.md
Normal file
351
demo/README-LOCAL.md
Normal file
@@ -0,0 +1,351 @@
|
||||
# Admin Framework Demo - 本地版本
|
||||
|
||||
本地开发版本,不依赖 CDN,所有依赖都从 node_modules 加载。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
demo/
|
||||
├── public/ # 静态资源
|
||||
│ └── index.html # HTML 模板
|
||||
├── src/ # 源代码
|
||||
│ ├── components/ # 自定义组件
|
||||
│ │ └── CustomPage.vue
|
||||
│ ├── main.js # 基础示例入口
|
||||
│ └── main-advanced.js # 高级示例入口
|
||||
├── package.json # 依赖配置
|
||||
├── webpack.config.js # Webpack 配置
|
||||
└── .babelrc # Babel 配置
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 构建 Admin Framework
|
||||
|
||||
首先需要构建框架(在项目根目录执行):
|
||||
|
||||
```bash
|
||||
# 回到项目根目录
|
||||
cd ..
|
||||
|
||||
# 生产构建
|
||||
npm run build
|
||||
|
||||
# 或开发构建(有 sourcemap)
|
||||
npm run build:dev
|
||||
```
|
||||
|
||||
### 2. 安装 Demo 依赖
|
||||
|
||||
```bash
|
||||
# 进入 demo 目录
|
||||
cd demo
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
```
|
||||
|
||||
### 3. 启动开发服务器
|
||||
|
||||
```bash
|
||||
# 启动基础示例
|
||||
npm run dev
|
||||
|
||||
# 浏览器会自动打开 http://localhost:8080
|
||||
```
|
||||
|
||||
### 4. 构建生产版本
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
npm run build
|
||||
|
||||
# 生成的文件在 demo/dist 目录
|
||||
```
|
||||
|
||||
## 切换示例
|
||||
|
||||
### 基础示例(默认)
|
||||
使用 `src/main.js` 作为入口,展示基本功能。
|
||||
|
||||
### 高级示例
|
||||
要切换到高级示例,修改 `webpack.config.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
entry: './src/main-advanced.js', // 改为 main-advanced.js
|
||||
// ... 其他配置
|
||||
}
|
||||
```
|
||||
|
||||
然后重新运行 `npm run dev`。
|
||||
|
||||
## 依赖说明
|
||||
|
||||
### 生产依赖
|
||||
- **vue**: ^2.6.14 - Vue 核心库
|
||||
- **vue-router**: ^3.5.3 - 路由管理
|
||||
- **vuex**: ^3.6.2 - 状态管理
|
||||
- **view-design**: ^4.7.0 - UI 组件库
|
||||
- **axios**: ^0.27.2 - HTTP 客户端
|
||||
|
||||
### 开发依赖
|
||||
- **webpack**: ^5.0.0 - 模块打包工具
|
||||
- **webpack-dev-server**: ^4.0.0 - 开发服务器
|
||||
- **babel-loader**: ^8.2.0 - ES6+ 转译
|
||||
- **vue-loader**: ^15.9.0 - Vue 单文件组件加载器
|
||||
- **html-webpack-plugin**: ^5.5.0 - HTML 生成插件
|
||||
|
||||
## 开发指南
|
||||
|
||||
### 1. 添加自定义页面
|
||||
|
||||
在 `src/components` 创建新组件:
|
||||
|
||||
```vue
|
||||
<!-- src/components/MyPage.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h1>我的页面</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MyPage'
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 注册到路由
|
||||
|
||||
在 `src/main.js` 或 `src/main-advanced.js` 中:
|
||||
|
||||
```javascript
|
||||
import MyPage from './components/MyPage.vue'
|
||||
|
||||
const customRoutes = [
|
||||
{
|
||||
path: '/my',
|
||||
component: AdminFramework.Main,
|
||||
children: [
|
||||
{
|
||||
path: 'page',
|
||||
component: MyPage,
|
||||
meta: { title: '我的页面' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
customRoutes.forEach(route => {
|
||||
AdminFramework.router.addRoute(route)
|
||||
})
|
||||
```
|
||||
|
||||
### 3. 添加 Vuex 模块
|
||||
|
||||
```javascript
|
||||
const myModule = {
|
||||
namespaced: true,
|
||||
state: { data: null },
|
||||
mutations: {
|
||||
SET_DATA(state, data) {
|
||||
state.data = data
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
fetchData({ commit }) {
|
||||
// 获取数据逻辑
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdminFramework.store.registerModule('myModule', myModule)
|
||||
```
|
||||
|
||||
### 4. 使用框架提供的组件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<!-- 表格组件 -->
|
||||
<Tables
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
/>
|
||||
|
||||
<!-- 上传组件 -->
|
||||
<UploadSingle
|
||||
v-model="fileUrl"
|
||||
:action="uploadUrl"
|
||||
/>
|
||||
|
||||
<!-- 富文本编辑器 -->
|
||||
<Editor v-model="content" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
columns: [],
|
||||
tableData: [],
|
||||
fileUrl: '',
|
||||
content: '',
|
||||
uploadUrl: this.$config.uploadUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## API 配置
|
||||
|
||||
修改 `src/main.js` 中的配置:
|
||||
|
||||
```javascript
|
||||
const config = {
|
||||
title: '系统标题',
|
||||
apiUrl: 'http://your-api.com/api/',
|
||||
uploadUrl: 'http://your-api.com/api/upload'
|
||||
}
|
||||
```
|
||||
|
||||
## HTTP 请求示例
|
||||
|
||||
### 在组件中使用
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
methods: {
|
||||
async fetchData() {
|
||||
try {
|
||||
// GET 请求
|
||||
const res = await this.$http.get('/api/users')
|
||||
console.log(res.data)
|
||||
|
||||
// POST 请求
|
||||
const res2 = await this.$http.post('/api/users', {
|
||||
name: '张三',
|
||||
age: 25
|
||||
})
|
||||
console.log(res2.data)
|
||||
} catch (error) {
|
||||
this.$Message.error('请求失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 工具函数使用
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
methods: {
|
||||
example() {
|
||||
// 日期格式化
|
||||
const formatted = this.$tools.formatDate(new Date(), 'yyyy-MM-dd')
|
||||
|
||||
// 深拷贝
|
||||
const copy = this.$tools.deepClone(obj)
|
||||
|
||||
// 防抖
|
||||
const debounced = this.$tools.debounce(() => {
|
||||
console.log('执行')
|
||||
}, 500)
|
||||
|
||||
// 节流
|
||||
const throttled = this.$tools.throttle(() => {
|
||||
console.log('执行')
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## UI 工具使用
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
methods: {
|
||||
example() {
|
||||
// 成功提示
|
||||
this.$uiTool.success('操作成功')
|
||||
|
||||
// 错误提示
|
||||
this.$uiTool.error('操作失败')
|
||||
|
||||
// 警告提示
|
||||
this.$uiTool.warning('警告信息')
|
||||
|
||||
// 确认对话框
|
||||
this.$uiTool.confirm('确定删除吗?').then(() => {
|
||||
// 确认后的操作
|
||||
}).catch(() => {
|
||||
// 取消后的操作
|
||||
})
|
||||
|
||||
// Loading
|
||||
const loading = this.$uiTool.loading('加载中...')
|
||||
setTimeout(() => loading.close(), 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 模块找不到
|
||||
确保先构建了 admin-framework:
|
||||
```bash
|
||||
cd .. && npm run build && cd demo
|
||||
```
|
||||
|
||||
### 2. 端口被占用
|
||||
修改 `webpack.config.js` 中的端口:
|
||||
```javascript
|
||||
devServer: {
|
||||
port: 8081, // 改为其他端口
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 热更新不生效
|
||||
检查 `devServer.hot` 配置是否为 `true`。
|
||||
|
||||
### 4. 样式不生效
|
||||
确保在入口文件中引入了 iView 样式:
|
||||
```javascript
|
||||
import 'view-design/dist/styles/iview.css'
|
||||
```
|
||||
|
||||
## 生产部署
|
||||
|
||||
### 1. 构建
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 2. 部署
|
||||
将 `demo/dist` 目录下的文件部署到服务器。
|
||||
|
||||
### 3. 注意事项
|
||||
- 确保后端 API 配置正确
|
||||
- 配置 Nginx 或其他服务器的路由重写规则(支持 Vue Router 的 history 模式)
|
||||
|
||||
## 更多示例
|
||||
|
||||
- 基础示例: 运行 `npm run dev`(默认)
|
||||
- 高级示例: 修改 webpack.config.js 的 entry 为 `./src/main-advanced.js`
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [Admin Framework 完整文档](../_doc/完整使用文档.md)
|
||||
- [Vue 官方文档](https://cn.vuejs.org/)
|
||||
- [Vue Router 文档](https://router.vuejs.org/zh/)
|
||||
- [Vuex 文档](https://vuex.vuejs.org/zh/)
|
||||
- [iView 文档](https://www.iviewui.com/)
|
||||
|
||||
251
demo/README.md
Normal file
251
demo/README.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Admin Framework Demo
|
||||
|
||||
本目录包含 Admin Framework 的使用示例,提供两种使用方式:
|
||||
|
||||
## 📁 文件说明
|
||||
|
||||
### 🌐 CDN 版本(快速体验)
|
||||
- **index.html** - 基础示例(CDN)
|
||||
- **advanced.html** - 高级示例(CDN)
|
||||
|
||||
适合快速体验,所有依赖从 CDN 加载,无需安装。
|
||||
|
||||
### 💻 本地开发版本(推荐开发使用)
|
||||
- **src/** - 源代码目录
|
||||
- **main.js** - 基础示例入口
|
||||
- **main-advanced.js** - 高级示例入口
|
||||
- **components/** - 自定义组件
|
||||
- **package.json** - 依赖配置
|
||||
- **webpack.config.js** - 构建配置
|
||||
|
||||
所有依赖本地安装,支持热更新,适合开发调试。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 使用方式
|
||||
|
||||
### 方式一:CDN 版本(快速体验)
|
||||
|
||||
#### index.html - 基础示例
|
||||
最简单的使用示例,展示如何:
|
||||
- 引入必要的依赖
|
||||
- 初始化框架
|
||||
- 创建基本应用
|
||||
|
||||
#### advanced.html - 高级示例
|
||||
完整的使用示例,展示如何:
|
||||
- 添加自定义页面组件
|
||||
- 注册自定义 Vuex 模块
|
||||
- 添加自定义路由
|
||||
- 配置路由守卫
|
||||
- 配置 Axios 拦截器
|
||||
- 使用组件映射
|
||||
|
||||
### 方式二:本地开发版本(推荐)
|
||||
|
||||
查看详细文档:[README-LOCAL.md](./README-LOCAL.md)
|
||||
|
||||
快速开始:
|
||||
```bash
|
||||
# 1. 构建框架(在项目根目录)
|
||||
cd ..
|
||||
npm run build
|
||||
|
||||
# 2. 安装 demo 依赖
|
||||
cd demo
|
||||
npm install
|
||||
|
||||
# 3. 启动开发服务器
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 使用步骤
|
||||
|
||||
### 1. 构建框架
|
||||
首先需要构建 admin-framework:
|
||||
|
||||
```bash
|
||||
# 生产构建(压缩,无 sourcemap)
|
||||
npm run build
|
||||
|
||||
# 开发构建(不压缩,有 sourcemap)
|
||||
npm run build:dev
|
||||
```
|
||||
|
||||
### 2. 启动示例
|
||||
|
||||
有以下几种方式启动示例:
|
||||
|
||||
#### 方式一:使用 Live Server(推荐)
|
||||
1. 安装 VS Code 的 Live Server 插件
|
||||
2. 右键 `index.html` 或 `advanced.html`
|
||||
3. 选择 "Open with Live Server"
|
||||
|
||||
#### 方式二:使用 HTTP 服务器
|
||||
```bash
|
||||
# 安装 http-server
|
||||
npm install -g http-server
|
||||
|
||||
# 在项目根目录运行
|
||||
http-server
|
||||
|
||||
# 访问
|
||||
# http://localhost:8080/demo/index.html
|
||||
# http://localhost:8080/demo/advanced.html
|
||||
```
|
||||
|
||||
#### 方式三:直接打开
|
||||
- 双击 HTML 文件在浏览器中打开
|
||||
- 注意:某些功能可能因跨域限制无法使用
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 基本配置
|
||||
```javascript
|
||||
const config = {
|
||||
title: '系统标题',
|
||||
apiUrl: 'http://your-api.com/api/', // API 基础地址
|
||||
uploadUrl: 'http://your-api.com/api/upload' // 上传接口地址
|
||||
}
|
||||
```
|
||||
|
||||
### 初始化框架
|
||||
```javascript
|
||||
framework.install(Vue, {
|
||||
config: config, // 配置对象
|
||||
ViewUI: iview, // iView 实例
|
||||
VueRouter: VueRouter, // Vue Router
|
||||
Vuex: Vuex, // Vuex
|
||||
createPersistedState: null, // Vuex 持久化插件(可选)
|
||||
componentMap: {} // 自定义组件映射
|
||||
})
|
||||
```
|
||||
|
||||
## 内置功能
|
||||
|
||||
### 1. 系统页面
|
||||
- **登录页面**: `/login`
|
||||
- **首页**: `/home`
|
||||
- **错误页面**: `/401`, `/404`, `/500`
|
||||
|
||||
### 2. 系统管理
|
||||
- **用户管理**: 系统用户的增删改查
|
||||
- **角色管理**: 角色权限管理
|
||||
- **菜单管理**: 动态菜单配置
|
||||
- **日志管理**: 系统操作日志
|
||||
|
||||
### 3. 高级功能
|
||||
- **动态表单**: 基于配置生成表单
|
||||
- **动态表格**: 可配置的数据表格
|
||||
- **文件上传**: 单文件/多文件上传
|
||||
- **富文本编辑器**: WangEditor
|
||||
- **代码编辑器**: Ace Editor
|
||||
|
||||
## API 使用
|
||||
|
||||
### HTTP 请求
|
||||
```javascript
|
||||
// GET 请求
|
||||
framework.http.get('/api/users').then(res => {
|
||||
console.log(res.data)
|
||||
})
|
||||
|
||||
// POST 请求
|
||||
framework.http.post('/api/users', {
|
||||
name: '张三',
|
||||
age: 25
|
||||
}).then(res => {
|
||||
console.log(res.data)
|
||||
})
|
||||
|
||||
// 在组件中使用
|
||||
this.$http.get('/api/users').then(res => {
|
||||
console.log(res.data)
|
||||
})
|
||||
```
|
||||
|
||||
### 工具函数
|
||||
```javascript
|
||||
// 使用框架提供的工具函数
|
||||
const tools = framework.tools
|
||||
|
||||
// 日期格式化
|
||||
tools.formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss')
|
||||
|
||||
// 深拷贝
|
||||
tools.deepClone(obj)
|
||||
|
||||
// 防抖
|
||||
tools.debounce(fn, 500)
|
||||
|
||||
// 节流
|
||||
tools.throttle(fn, 500)
|
||||
```
|
||||
|
||||
### UI 工具
|
||||
```javascript
|
||||
// 使用 UI 工具
|
||||
const uiTool = framework.uiTool
|
||||
|
||||
// 成功提示
|
||||
uiTool.success('操作成功')
|
||||
|
||||
// 错误提示
|
||||
uiTool.error('操作失败')
|
||||
|
||||
// 确认对话框
|
||||
uiTool.confirm('确定删除吗?').then(() => {
|
||||
// 确认后的操作
|
||||
})
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 依赖库版本
|
||||
确保使用以下版本的依赖库:
|
||||
- Vue: 2.6.x
|
||||
- Vue Router: 3.x
|
||||
- Vuex: 3.x
|
||||
- iView (view-design): 4.x
|
||||
- Axios: 0.21.x+
|
||||
|
||||
### 2. 路径问题
|
||||
如果无法加载 admin-framework.js,检查路径是否正确:
|
||||
```html
|
||||
<!-- 确保路径指向正确的文件 -->
|
||||
<script src="../dist/admin-framework.js"></script>
|
||||
```
|
||||
|
||||
### 3. API 地址
|
||||
记得修改配置中的 API 地址为实际的后端地址:
|
||||
```javascript
|
||||
const config = {
|
||||
apiUrl: 'http://your-real-api.com/api/',
|
||||
uploadUrl: 'http://your-real-api.com/api/upload'
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 跨域问题
|
||||
如果遇到跨域问题,需要配置后端 CORS 或使用代理。
|
||||
|
||||
## 开发建议
|
||||
|
||||
1. **开发时使用 build:dev**
|
||||
- 生成 sourcemap,方便调试
|
||||
- 代码不压缩,易读
|
||||
|
||||
2. **生产时使用 build**
|
||||
- 代码压缩,体积小
|
||||
- 无 sourcemap,安全
|
||||
|
||||
3. **使用浏览器调试工具**
|
||||
```javascript
|
||||
// 所有实例都挂载到 window 上,方便调试
|
||||
window.app // Vue 实例
|
||||
window.framework // 框架实例
|
||||
```
|
||||
|
||||
## 更多信息
|
||||
|
||||
查看完整文档:`../_doc/完整使用文档.md`
|
||||
|
||||
218
demo/advanced.html
Normal file
218
demo/advanced.html
Normal file
@@ -0,0 +1,218 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Framework - 高级示例</title>
|
||||
|
||||
<!-- 引入 iView 样式 -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/view-design@4.7.0/dist/styles/iview.css">
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
|
||||
}
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<!-- 引入依赖库 -->
|
||||
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
|
||||
<script src="https://unpkg.com/vue-router@3.5.3/dist/vue-router.js"></script>
|
||||
<script src="https://unpkg.com/vuex@3.6.2/dist/vuex.js"></script>
|
||||
<script src="https://unpkg.com/view-design@4.7.0/dist/iview.js"></script>
|
||||
<script src="https://unpkg.com/axios@0.27.2/dist/axios.js"></script>
|
||||
|
||||
<!-- 引入 admin-framework -->
|
||||
<script src="../dist/admin-framework.js"></script>
|
||||
|
||||
<script>
|
||||
// 获取框架实例
|
||||
const framework = window.AdminFramework
|
||||
|
||||
// ========== 1. 自定义页面组件 ==========
|
||||
const CustomPage = {
|
||||
name: 'CustomPage',
|
||||
template: `
|
||||
<div style="padding: 20px;">
|
||||
<Card>
|
||||
<p slot="title">自定义页面</p>
|
||||
<p>这是一个自定义页面示例</p>
|
||||
<p>当前时间: {{ currentTime }}</p>
|
||||
<Button type="primary" @click="handleClick">点击测试</Button>
|
||||
</Card>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
currentTime: new Date().toLocaleString()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.$Message.success('按钮点击成功!')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 定时更新时间
|
||||
this.timer = setInterval(() => {
|
||||
this.currentTime = new Date().toLocaleString()
|
||||
}, 1000)
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 2. 自定义 Vuex 模块 ==========
|
||||
const customModule = {
|
||||
namespaced: true,
|
||||
state: {
|
||||
customData: '自定义数据'
|
||||
},
|
||||
getters: {
|
||||
customData: state => state.customData
|
||||
},
|
||||
mutations: {
|
||||
SET_CUSTOM_DATA(state, data) {
|
||||
state.customData = data
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
updateCustomData({ commit }, data) {
|
||||
commit('SET_CUSTOM_DATA', data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 3. 配置参数 ==========
|
||||
const config = {
|
||||
title: 'Admin Framework 高级示例',
|
||||
apiUrl: 'http://localhost:3000/api/',
|
||||
uploadUrl: 'http://localhost:3000/api/upload',
|
||||
// 其他自定义配置
|
||||
theme: 'light',
|
||||
language: 'zh-CN'
|
||||
}
|
||||
|
||||
// ========== 4. 组件映射(用于动态路由加载) ==========
|
||||
const componentMap = {
|
||||
'custom/page': CustomPage,
|
||||
'custom/page.vue': CustomPage
|
||||
}
|
||||
|
||||
// ========== 5. 初始化框架 ==========
|
||||
framework.install(Vue, {
|
||||
config: config,
|
||||
ViewUI: iview,
|
||||
VueRouter: VueRouter,
|
||||
Vuex: Vuex,
|
||||
createPersistedState: null,
|
||||
componentMap: componentMap
|
||||
})
|
||||
|
||||
// ========== 6. 添加自定义 Vuex 模块 ==========
|
||||
framework.store.registerModule('custom', customModule)
|
||||
|
||||
// ========== 7. 添加自定义路由 ==========
|
||||
const customRoutes = [
|
||||
{
|
||||
path: '/custom',
|
||||
component: framework.Main, // 使用框架的主布局
|
||||
children: [
|
||||
{
|
||||
path: 'page',
|
||||
name: 'custom_page',
|
||||
component: CustomPage,
|
||||
meta: {
|
||||
title: '自定义页面',
|
||||
hideInMenu: false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 添加路由
|
||||
customRoutes.forEach(route => {
|
||||
framework.router.addRoute(route)
|
||||
})
|
||||
|
||||
// ========== 8. 路由守卫(可选) ==========
|
||||
framework.router.beforeEach((to, from, next) => {
|
||||
// 可以在这里添加权限验证等逻辑
|
||||
console.log('路由跳转:', from.path, '->', to.path)
|
||||
next()
|
||||
})
|
||||
|
||||
// ========== 9. Axios 拦截器配置(可选) ==========
|
||||
framework.http.interceptors.request.use(
|
||||
config => {
|
||||
// 在请求发送前做些什么
|
||||
console.log('发送请求:', config.url)
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
framework.http.interceptors.response.use(
|
||||
response => {
|
||||
// 对响应数据做些什么
|
||||
console.log('收到响应:', response.config.url)
|
||||
return response
|
||||
},
|
||||
error => {
|
||||
// 对响应错误做些什么
|
||||
console.error('请求错误:', error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// ========== 10. 创建 Vue 实例 ==========
|
||||
const app = new Vue({
|
||||
router: framework.router,
|
||||
store: framework.store,
|
||||
render: h => h('router-view'),
|
||||
created() {
|
||||
console.log('=== Admin Framework 高级示例启动 ===')
|
||||
console.log('配置信息:', this.$config)
|
||||
console.log('可用路由:', this.$router.options.routes)
|
||||
}
|
||||
})
|
||||
|
||||
// ========== 11. 挂载应用 ==========
|
||||
app.$mount('#app')
|
||||
|
||||
// ========== 12. 全局暴露(方便调试) ==========
|
||||
window.app = app
|
||||
window.rootVue = app
|
||||
window.framework = framework
|
||||
|
||||
// ========== 13. 打印框架信息 ==========
|
||||
console.log('框架版本:', framework.version)
|
||||
console.log('框架实例:', framework)
|
||||
console.log('路由实例:', framework.router)
|
||||
console.log('Store 实例:', framework.store)
|
||||
console.log('工具函数:', framework.tools)
|
||||
console.log('UI 工具:', framework.uiTool)
|
||||
console.log('HTTP 实例:', framework.http)
|
||||
|
||||
// ========== 14. 提示信息 ==========
|
||||
setTimeout(() => {
|
||||
iview.Message.success({
|
||||
content: 'Admin Framework 高级示例启动成功!',
|
||||
duration: 3
|
||||
})
|
||||
}, 500)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
77
demo/index.html
Normal file
77
demo/index.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Framework Demo</title>
|
||||
|
||||
<!-- 引入 iView 样式 -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/view-design@4.7.0/dist/styles/iview.css">
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
|
||||
}
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<!-- 引入依赖库 -->
|
||||
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
|
||||
<script src="https://unpkg.com/vue-router@3.5.3/dist/vue-router.js"></script>
|
||||
<script src="https://unpkg.com/vuex@3.6.2/dist/vuex.js"></script>
|
||||
<script src="https://unpkg.com/view-design@4.7.0/dist/iview.js"></script>
|
||||
<script src="https://unpkg.com/axios@0.27.2/dist/axios.js"></script>
|
||||
|
||||
<!-- 引入 admin-framework -->
|
||||
<script src="../dist/admin-framework.js"></script>
|
||||
|
||||
<script>
|
||||
// 获取框架实例
|
||||
const framework = window.AdminFramework
|
||||
|
||||
// 配置参数
|
||||
const config = {
|
||||
title: 'Admin Framework Demo',
|
||||
apiUrl: 'http://localhost:3000/api/', // 修改为你的 API 地址
|
||||
uploadUrl: 'http://localhost:3000/api/upload' // 修改为你的上传地址
|
||||
}
|
||||
|
||||
// 初始化框架
|
||||
framework.install(Vue, {
|
||||
config: config,
|
||||
ViewUI: iview,
|
||||
VueRouter: VueRouter,
|
||||
Vuex: Vuex,
|
||||
createPersistedState: null, // 如需持久化,需引入 vuex-persistedstate
|
||||
componentMap: {} // 可添加自定义组件映射
|
||||
})
|
||||
|
||||
// 创建 Vue 实例
|
||||
const app = new Vue({
|
||||
router: framework.router,
|
||||
store: framework.store,
|
||||
render: h => h('router-view')
|
||||
})
|
||||
|
||||
// 挂载应用
|
||||
app.$mount('#app')
|
||||
|
||||
// 将 app 实例挂载到 window,方便调试
|
||||
window.app = app
|
||||
window.rootVue = app
|
||||
|
||||
console.log('Admin Framework Demo 启动成功!')
|
||||
console.log('框架实例:', framework)
|
||||
console.log('路由实例:', framework.router)
|
||||
console.log('Store 实例:', framework.store)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
7257
demo/package-lock.json
generated
Normal file
7257
demo/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
demo/package.json
Normal file
33
demo/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "admin-framework-demo",
|
||||
"version": "1.0.0",
|
||||
"description": "Admin Framework 本地示例",
|
||||
"scripts": {
|
||||
"install:deps": "npm install",
|
||||
"dev": "webpack serve --mode development --open",
|
||||
"build": "webpack --mode production"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.27.2",
|
||||
"view-design": "^4.7.0",
|
||||
"vue": "^2.6.14",
|
||||
"vue-router": "^3.5.3",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.0",
|
||||
"@babel/preset-env": "^7.12.0",
|
||||
"babel-loader": "^8.2.0",
|
||||
"css-loader": "^5.0.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"vue-loader": "^15.9.0",
|
||||
"vue-style-loader": "^4.1.0",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"webpack": "^5.0.0",
|
||||
"webpack-cli": "^4.0.0",
|
||||
"webpack-dev-server": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
12
demo/public/index.html
Normal file
12
demo/public/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Framework Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
21
demo/src/api/ad/sysAdServer.js
Normal file
21
demo/src/api/ad/sysAdServer.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import http from "@/libs/http";
|
||||
|
||||
class SysAdServer {
|
||||
async getAll(param) {
|
||||
return await http.get("/sys_ad/index", param);
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
return await http.post("/sys_ad/add", row);
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
return await http.post("/sys_ad/edit", row);
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
return await http.post("/sys_ad/del", row);
|
||||
}
|
||||
}
|
||||
const sysAdServer = new SysAdServer();
|
||||
export default sysAdServer;
|
||||
35
demo/src/api/ai/ai_messages_server.js
Normal file
35
demo/src/api/ai/ai_messages_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class ai_messagesClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/ai_messages/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/ai_messages/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/ai_messages/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/ai_messages/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/ai_messages/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/ai_messages/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const ai_messagesServer = new ai_messagesClServer();
|
||||
export default ai_messagesServer;
|
||||
53
demo/src/api/ball/game_comments_server.js
Normal file
53
demo/src/api/ball/game_comments_server.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取球局评论列表
|
||||
getGameCommentsList: (params) => {
|
||||
return http.post('/game_comments/page', params)
|
||||
},
|
||||
|
||||
// 获取所有球局评论
|
||||
getAllGameComments: (params) => {
|
||||
return http.get('/game_comments/all', params)
|
||||
},
|
||||
|
||||
// 获取球局评论详情
|
||||
getGameCommentDetail: (params) => {
|
||||
return http.get('/game_comments/detail', params)
|
||||
},
|
||||
|
||||
// 新增球局评论
|
||||
addGameComment: (params) => {
|
||||
return http.post('/game_comments/add', params)
|
||||
},
|
||||
|
||||
// 更新球局评论
|
||||
updateGameComment: (params) => {
|
||||
return http.post('/game_comments/edit', params)
|
||||
},
|
||||
|
||||
// 删除球局评论
|
||||
deleteGameComment: (params) => {
|
||||
return http.post('/game_comments/del', params)
|
||||
},
|
||||
|
||||
// 批量删除球局评论
|
||||
batchDeleteGameComments: (params) => {
|
||||
return http.post('/game_comments/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出球局评论数据
|
||||
exportGameComments: (params) => {
|
||||
return http.post('/game_comments/export', params)
|
||||
},
|
||||
|
||||
// 审核评论
|
||||
auditComment: (params) => {
|
||||
return http.post('/game_comments/audit', params)
|
||||
},
|
||||
|
||||
// 获取评论回复
|
||||
getCommentReplies: (params) => {
|
||||
return http.get('/game_comments/replies', params)
|
||||
}
|
||||
}
|
||||
48
demo/src/api/ball/game_participants_server.js
Normal file
48
demo/src/api/ball/game_participants_server.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取球局参与者列表
|
||||
getGameParticipantsList: (params) => {
|
||||
return http.post('/game_participants/page', params)
|
||||
},
|
||||
|
||||
// 获取所有球局参与者
|
||||
getAllGameParticipants: (params) => {
|
||||
return http.get('/game_participants/all', params)
|
||||
},
|
||||
|
||||
// 获取球局参与者详情
|
||||
getGameParticipantDetail: (params) => {
|
||||
return http.get('/game_participants/detail', params)
|
||||
},
|
||||
|
||||
// 新增球局参与者
|
||||
addGameParticipant: (params) => {
|
||||
return http.post('/game_participants/add', params)
|
||||
},
|
||||
|
||||
// 更新球局参与者
|
||||
updateGameParticipant: (params) => {
|
||||
return http.post('/game_participants/edit', params)
|
||||
},
|
||||
|
||||
// 删除球局参与者
|
||||
deleteGameParticipant: (params) => {
|
||||
return http.post('/game_participants/del', params)
|
||||
},
|
||||
|
||||
// 批量删除球局参与者
|
||||
batchDeleteGameParticipants: (params) => {
|
||||
return http.post('/game_participants/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出球局参与者数据
|
||||
exportGameParticipants: (params) => {
|
||||
return http.post('/game_participants/export', params)
|
||||
},
|
||||
|
||||
// 更新参与者状态
|
||||
updateParticipantStatus: (params) => {
|
||||
return http.post('/game_participants/update_status', params)
|
||||
}
|
||||
}
|
||||
50
demo/src/api/ball/games_server.js
Normal file
50
demo/src/api/ball/games_server.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import http from '@/libs/http';
|
||||
class gamesClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/gme_games/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/gme_games/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/gme_games/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/gme_games/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/gme_games/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/gme_games/del', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async cancel(row) {
|
||||
let res = await http.post('/gme_games/cancel', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async updateStatus(row) {
|
||||
let res = await http.post('/gme_games/update_status', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async statistics() {
|
||||
let res = await http.get('/gme_games/statistics', {});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const gamesServer = new gamesClServer();
|
||||
export default gamesServer;
|
||||
38
demo/src/api/ball/payment_orders_server.js
Normal file
38
demo/src/api/ball/payment_orders_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http';
|
||||
class paymentOrdersClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/pay_orders/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/pay_orders/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/pay_orders/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/pay_orders/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/pay_orders/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/pay_orders/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const paymentOrdersServer = new paymentOrdersClServer();
|
||||
export default paymentOrdersServer;
|
||||
|
||||
36
demo/src/api/ball/resources_server.js
Normal file
36
demo/src/api/ball/resources_server.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
// 获取资源列表(分页)
|
||||
export function getList(params) {
|
||||
return http.post('/gal_resources/page', params)
|
||||
}
|
||||
|
||||
// 添加资源
|
||||
export function add(params) {
|
||||
return http.post('/gal_resources/add', params)
|
||||
}
|
||||
|
||||
// 编辑资源
|
||||
export function edit(params) {
|
||||
return http.post('/gal_resources/edit', params)
|
||||
}
|
||||
|
||||
// 删除资源
|
||||
export function del(params) {
|
||||
return http.post('/gal_resources/del', params)
|
||||
}
|
||||
|
||||
// 导出资源
|
||||
export function exportData(params) {
|
||||
return http.fileExport('/gal_resources/export', params)
|
||||
}
|
||||
|
||||
// 获取所有资源
|
||||
export function getAll(params) {
|
||||
return http.get('/gal_resources/all', params)
|
||||
}
|
||||
|
||||
// 获取资源详情
|
||||
export function getDetail(params) {
|
||||
return http.get('/gal_resources/detail', params)
|
||||
}
|
||||
38
demo/src/api/ball/venues_server.js
Normal file
38
demo/src/api/ball/venues_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http';
|
||||
class venuesClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/ven_venues/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/ven_venues/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/ven_venues/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/ven_venues/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/ven_venues/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/ven_venues/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const venuesServer = new venuesClServer();
|
||||
export default venuesServer;
|
||||
|
||||
36
demo/src/api/ball/wallet_transactions_server.js
Normal file
36
demo/src/api/ball/wallet_transactions_server.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import http from '@/libs/http';
|
||||
|
||||
class walletTransactionsClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/wch_wallet_transactions/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/wch_wallet_transactions/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/wch_wallet_transactions/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async detail(id) {
|
||||
let res= await http.get('/wch_wallet_transactions/detail', { id });
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/wch_wallet_transactions/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async statistics() {
|
||||
let res = await http.get('/wch_wallet_transactions/statistics', {});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const walletTransactionsServer = new walletTransactionsClServer();
|
||||
export default walletTransactionsServer;
|
||||
36
demo/src/api/ball/wallets_server.js
Normal file
36
demo/src/api/ball/wallets_server.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import http from '@/libs/http';
|
||||
|
||||
class walletsClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/wch_wallets/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/wch_wallets/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/wch_wallets/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/wch_wallets/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async adjustBalance(row) {
|
||||
let res= await http.post('/wch_wallets/adjust_balance', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async statistics() {
|
||||
let res = await http.get('/wch_wallets/statistics', {});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const walletsServer = new walletsClServer();
|
||||
export default walletsServer;
|
||||
38
demo/src/api/ball/wch_users_server.js
Normal file
38
demo/src/api/ball/wch_users_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http';
|
||||
class wch_usersClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/wch_users/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/wch_users/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/wch_users/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/wch_users/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/wch_users/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/wch_users/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const wch_usersServer = new wch_usersClServer();
|
||||
export default wch_usersServer;
|
||||
|
||||
33
demo/src/api/business/games_server.js
Normal file
33
demo/src/api/business/games_server.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import request from '@/libs/http'
|
||||
|
||||
export const getList = (params) => {
|
||||
return request({
|
||||
url: '/business/games/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export const add = (data) => {
|
||||
return request({
|
||||
url: '/business/games',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const edit = (data) => {
|
||||
return request({
|
||||
url: '/business/games',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const del = (params) => {
|
||||
return request({
|
||||
url: '/business/games',
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
}
|
||||
48
demo/src/api/business/hot_city_qr_config_server.js
Normal file
48
demo/src/api/business/hot_city_qr_config_server.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取热门城市二维码配置列表
|
||||
getHotCityQrConfigsList: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/page', params)
|
||||
},
|
||||
|
||||
// 获取所有热门城市二维码配置
|
||||
getAllHotCityQrConfigs: (params) => {
|
||||
return http.get('/wch_hot_city_qr_config/all', params)
|
||||
},
|
||||
|
||||
// 获取热门城市二维码配置详情
|
||||
getHotCityQrConfigDetail: (params) => {
|
||||
return http.get('/wch_hot_city_qr_config/detail', params)
|
||||
},
|
||||
|
||||
// 新增热门城市二维码配置
|
||||
addHotCityQrConfig: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/add', params)
|
||||
},
|
||||
|
||||
// 更新热门城市二维码配置
|
||||
updateHotCityQrConfig: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/edit', params)
|
||||
},
|
||||
|
||||
// 删除热门城市二维码配置
|
||||
deleteHotCityQrConfig: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/del', params)
|
||||
},
|
||||
|
||||
// 批量删除热门城市二维码配置
|
||||
batchDeleteHotCityQrConfigs: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出热门城市二维码配置
|
||||
exportHotCityQrConfigs: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/export', params)
|
||||
},
|
||||
|
||||
// 生成二维码
|
||||
generateQRCode: (params) => {
|
||||
return http.post('/wch_hot_city_qr_config/generate_qr', params)
|
||||
}
|
||||
}
|
||||
39
demo/src/api/business/hot_city_qr_server.js
Normal file
39
demo/src/api/business/hot_city_qr_server.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取列表(分页)
|
||||
page(params) {
|
||||
return http.get('/wch_hot_city_qr_config/list', params)
|
||||
},
|
||||
|
||||
// 获取所有(不分页)
|
||||
all() {
|
||||
return http.get('/wch_hot_city_qr_config/all')
|
||||
},
|
||||
|
||||
// 获取详情
|
||||
detail(id) {
|
||||
return http.get(`/wch_hot_city_qr_config/detail/${id}`)
|
||||
},
|
||||
|
||||
// 新增
|
||||
add(data) {
|
||||
return http.post('/wch_hot_city_qr_config/create', data)
|
||||
},
|
||||
|
||||
// 编辑
|
||||
edit(id, data) {
|
||||
return http.post(`/wch_hot_city_qr_config/update/${id}`, data)
|
||||
},
|
||||
|
||||
// 删除
|
||||
del(id) {
|
||||
return http.post(`/wch_hot_city_qr_config/delete/${id}`)
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
batchDel(ids) {
|
||||
return http.post('/wch_hot_city_qr_config/batch_delete', { ids })
|
||||
}
|
||||
}
|
||||
|
||||
38
demo/src/api/cote/info_server.js
Normal file
38
demo/src/api/cote/info_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http';
|
||||
class infoClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/inf_info/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/inf_info/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/inf_info/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/inf_info/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/inf_info/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/inf_info/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const infoServer = new infoClServer();
|
||||
export default infoServer;
|
||||
|
||||
38
demo/src/api/cote/info_type_server.js
Normal file
38
demo/src/api/cote/info_type_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http';
|
||||
class info_typeClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/inf_info_type/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/inf_info_type/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/inf_info_type/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/inf_info_type/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/inf_info_type/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/inf_info_type/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const info_typeServer = new info_typeClServer();
|
||||
export default info_typeServer;
|
||||
|
||||
26
demo/src/api/home/homeServer.js
Normal file
26
demo/src/api/home/homeServer.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import http from "@/libs/http";
|
||||
class HomeServer {
|
||||
// 获取订单统计
|
||||
async getOderCount() {
|
||||
let res = await http.get("/order/count");
|
||||
return res;
|
||||
}
|
||||
|
||||
async getUserCount() {
|
||||
let res = await http.get("/user/count");
|
||||
return res;
|
||||
}
|
||||
|
||||
async getSalesRank() {
|
||||
let res = await http.get("/index/salesRank");
|
||||
return res;
|
||||
}
|
||||
|
||||
async userRecommendRank() {
|
||||
let res = await http.get("/index/userRecommendRank");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const homeServer = new HomeServer();
|
||||
export default homeServer;
|
||||
28
demo/src/api/message/msg_notifications_server.js
Normal file
28
demo/src/api/message/msg_notifications_server.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取消息通知列表
|
||||
page: (params) => {
|
||||
return http.post('/msg_notifications/page', params)
|
||||
},
|
||||
|
||||
// 新增消息通知
|
||||
add: (params) => {
|
||||
return http.post('/msg_notifications/add', params)
|
||||
},
|
||||
|
||||
// 更新消息通知
|
||||
edit: (params) => {
|
||||
return http.post('/msg_notifications/edit', params)
|
||||
},
|
||||
|
||||
// 删除消息通知
|
||||
del: (params) => {
|
||||
return http.post('/msg_notifications/del', params)
|
||||
},
|
||||
|
||||
// 导出消息通知数据
|
||||
exportCsv: (params) => {
|
||||
return http.get('/msg_notifications/export', params)
|
||||
}
|
||||
}
|
||||
35
demo/src/api/ntrp/ntr_questions_server.js
Normal file
35
demo/src/api/ntrp/ntr_questions_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class ntr_questionsClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/ntr_questions/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/ntr_questions/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/ntr_questions/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/ntr_questions/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/ntr_questions/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/ntr_questions/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const ntr_questionsServer = new ntr_questionsClServer();
|
||||
export default ntr_questionsServer;
|
||||
35
demo/src/api/ntrp/ntr_records_server.js
Normal file
35
demo/src/api/ntrp/ntr_records_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class ntr_recordsClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/ntr_records/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/ntr_records/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/ntr_records/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/ntr_records/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/ntr_records/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/ntr_records/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const ntr_recordsServer = new ntr_recordsClServer();
|
||||
export default ntr_recordsServer;
|
||||
53
demo/src/api/order/frozen_funds_server.js
Normal file
53
demo/src/api/order/frozen_funds_server.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取冻结资金列表
|
||||
getFrozenFundsList: (params) => {
|
||||
return http.post('/frozen_funds/page', params)
|
||||
},
|
||||
|
||||
// 获取所有冻结资金
|
||||
getAllFrozenFunds: (params) => {
|
||||
return http.get('/frozen_funds/all', params)
|
||||
},
|
||||
|
||||
// 获取冻结资金详情
|
||||
getFrozenFundDetail: (params) => {
|
||||
return http.get('/frozen_funds/detail', params)
|
||||
},
|
||||
|
||||
// 新增冻结资金
|
||||
addFrozenFund: (params) => {
|
||||
return http.post('/frozen_funds/add', params)
|
||||
},
|
||||
|
||||
// 更新冻结资金
|
||||
updateFrozenFund: (params) => {
|
||||
return http.post('/frozen_funds/edit', params)
|
||||
},
|
||||
|
||||
// 删除冻结资金
|
||||
deleteFrozenFund: (params) => {
|
||||
return http.post('/frozen_funds/del', params)
|
||||
},
|
||||
|
||||
// 批量删除冻结资金
|
||||
batchDeleteFrozenFunds: (params) => {
|
||||
return http.post('/frozen_funds/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出冻结资金数据
|
||||
exportFrozenFunds: (params) => {
|
||||
return http.post('/frozen_funds/export', params)
|
||||
},
|
||||
|
||||
// 解冻资金
|
||||
unfreezeFund: (params) => {
|
||||
return http.post('/frozen_funds/unfreeze', params)
|
||||
},
|
||||
|
||||
// 获取冻结统计
|
||||
getFrozenStats: (params) => {
|
||||
return http.get('/frozen_funds/stats', params)
|
||||
}
|
||||
}
|
||||
28
demo/src/api/order/order_status_server.js
Normal file
28
demo/src/api/order/order_status_server.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取订单状态列表
|
||||
getOrderStatusList: (params) => {
|
||||
return http.post('/order/status/list', params)
|
||||
},
|
||||
|
||||
// 批量更新订单状态
|
||||
batchUpdateOrderStatus: (params) => {
|
||||
return http.post('/order/status/batch_update', params)
|
||||
},
|
||||
|
||||
// 更新单个订单状态
|
||||
updateSingleOrderStatus: (params) => {
|
||||
return http.post('/order/status/update', params)
|
||||
},
|
||||
|
||||
// 取消订单
|
||||
cancelOrder: (params) => {
|
||||
return http.post('/order/cancel', params)
|
||||
},
|
||||
|
||||
// 获取订单状态流转日志
|
||||
getOrderStatusLogs: (params) => {
|
||||
return http.post('/order/status/logs', params)
|
||||
}
|
||||
}
|
||||
73
demo/src/api/order/payment_orders_server.js
Normal file
73
demo/src/api/order/payment_orders_server.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取支付订单列表
|
||||
getPaymentOrdersList: (params) => {
|
||||
return http.post('/pay_orders/page', params)
|
||||
},
|
||||
|
||||
// 获取所有支付订单
|
||||
getAllPaymentOrders: (params) => {
|
||||
return http.get('/pay_orders/all', params)
|
||||
},
|
||||
|
||||
// 获取支付订单详情
|
||||
getPaymentOrderDetail: (params) => {
|
||||
return http.get('/pay_orders/detail', params)
|
||||
},
|
||||
|
||||
// 新增支付订单
|
||||
addPaymentOrder: (params) => {
|
||||
return http.post('/pay_orders/add', params)
|
||||
},
|
||||
|
||||
// 更新支付订单
|
||||
updatePaymentOrder: (params) => {
|
||||
return http.post('/pay_orders/edit', params)
|
||||
},
|
||||
|
||||
// 删除支付订单
|
||||
deletePaymentOrder: (params) => {
|
||||
return http.post('/pay_orders/del', params)
|
||||
},
|
||||
|
||||
// 批量删除支付订单
|
||||
batchDeletePaymentOrders: (params) => {
|
||||
return http.post('/pay_orders/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出支付订单
|
||||
exportPaymentOrders: (params) => {
|
||||
return http.post('/pay_orders/export', params)
|
||||
},
|
||||
|
||||
// 获取支付订单统计
|
||||
getPaymentOrderStats: (params) => {
|
||||
return http.post('/pay_orders/statistics', params)
|
||||
},
|
||||
|
||||
// 更新订单状态
|
||||
updateOrderStatus: (params) => {
|
||||
return http.post('/pay_orders/update_status', params)
|
||||
},
|
||||
|
||||
// 取消订单
|
||||
cancelPaymentOrder: (id) => {
|
||||
return http.post(`/pay_orders/cancel/${id}`)
|
||||
},
|
||||
|
||||
// 获取订单支付详情
|
||||
getOrderPaymentDetail: (params) => {
|
||||
return http.get('/pay_orders/payment_detail', params)
|
||||
},
|
||||
|
||||
// 重新发起支付
|
||||
retryPayment: (params) => {
|
||||
return http.post('/pay_orders/retry_payment', params)
|
||||
},
|
||||
|
||||
// 获取订单退款信息
|
||||
getOrderRefundInfo: (params) => {
|
||||
return http.get('/pay_orders/refund_info', params)
|
||||
}
|
||||
}
|
||||
23
demo/src/api/order/payment_stats_server.js
Normal file
23
demo/src/api/order/payment_stats_server.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取支付统计数据
|
||||
getPaymentStats: (params) => {
|
||||
return http.post('/payment/stats', params)
|
||||
},
|
||||
|
||||
// 获取支付趋势数据
|
||||
getPaymentTrend: (params) => {
|
||||
return http.post('/payment/trend', params)
|
||||
},
|
||||
|
||||
// 获取订单状态分布
|
||||
getOrderStatusDistribution: (params) => {
|
||||
return http.post('/payment/status_distribution', params)
|
||||
},
|
||||
|
||||
// 导出支付统计
|
||||
exportPaymentStats: (params) => {
|
||||
return http.post('/payment/export_stats', params)
|
||||
}
|
||||
}
|
||||
35
demo/src/api/order/transfer_details_server.js
Normal file
35
demo/src/api/order/transfer_details_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class transfer_detailsClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/transfer_details/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/transfer_details/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/transfer_details/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/transfer_details/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/transfer_details/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/transfer_details/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const transfer_detailsServer = new transfer_detailsClServer();
|
||||
export default transfer_detailsServer;
|
||||
53
demo/src/api/order/wallet_transactions_server.js
Normal file
53
demo/src/api/order/wallet_transactions_server.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取钱包交易记录列表
|
||||
getWalletTransactionsList: (params) => {
|
||||
return http.post('/wallet_transactions/page', params)
|
||||
},
|
||||
|
||||
// 获取所有钱包交易记录
|
||||
getAllWalletTransactions: (params) => {
|
||||
return http.get('/wallet_transactions/all', params)
|
||||
},
|
||||
|
||||
// 获取钱包交易记录详情
|
||||
getWalletTransactionDetail: (params) => {
|
||||
return http.get('/wallet_transactions/detail', params)
|
||||
},
|
||||
|
||||
// 新增钱包交易记录
|
||||
addWalletTransaction: (params) => {
|
||||
return http.post('/wallet_transactions/add', params)
|
||||
},
|
||||
|
||||
// 更新钱包交易记录
|
||||
updateWalletTransaction: (params) => {
|
||||
return http.post('/wallet_transactions/edit', params)
|
||||
},
|
||||
|
||||
// 删除钱包交易记录
|
||||
deleteWalletTransaction: (params) => {
|
||||
return http.post('/wallet_transactions/del', params)
|
||||
},
|
||||
|
||||
// 批量删除钱包交易记录
|
||||
batchDeleteWalletTransactions: (params) => {
|
||||
return http.post('/wallet_transactions/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出钱包交易记录
|
||||
exportWalletTransactions: (params) => {
|
||||
return http.post('/wallet_transactions/export', params)
|
||||
},
|
||||
|
||||
// 获取交易统计
|
||||
getTransactionStats: (params) => {
|
||||
return http.get('/wallet_transactions/stats', params)
|
||||
},
|
||||
|
||||
// 获取用户交易记录
|
||||
getUserTransactions: (params) => {
|
||||
return http.get('/wallet_transactions/user', params)
|
||||
}
|
||||
}
|
||||
88
demo/src/api/order/wch_wallets_server.js
Normal file
88
demo/src/api/order/wch_wallets_server.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取用户钱包列表
|
||||
getWalletsList: (params) => {
|
||||
return http.post('/wch_wallets/page', params)
|
||||
},
|
||||
|
||||
// 获取所有钱包
|
||||
getAllWallets: (params) => {
|
||||
return http.get('/wch_wallets/all', params)
|
||||
},
|
||||
|
||||
// 获取钱包详情
|
||||
getWalletDetail: (params) => {
|
||||
return http.get('/wch_wallets/detail', params)
|
||||
},
|
||||
|
||||
// 新增钱包
|
||||
addWallet: (params) => {
|
||||
return http.post('/wch_wallets/add', params)
|
||||
},
|
||||
|
||||
// 更新钱包
|
||||
updateWallet: (params) => {
|
||||
return http.post('/wch_wallets/edit', params)
|
||||
},
|
||||
|
||||
// 删除钱包
|
||||
deleteWallet: (params) => {
|
||||
return http.post('/wallets/delete', params)
|
||||
},
|
||||
|
||||
// 批量删除钱包
|
||||
batchDeleteWallets: (params) => {
|
||||
return http.post('/wallets/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出钱包数据
|
||||
exportWallets: (params) => {
|
||||
return http.post('/wallets/export', params)
|
||||
},
|
||||
|
||||
// 获取钱包统计
|
||||
getWalletStats: (params) => {
|
||||
return http.post('/wallets/stats', params)
|
||||
},
|
||||
|
||||
// 更新钱包状态
|
||||
updateWalletStatus: (params) => {
|
||||
return http.post('/wallets/update_status', params)
|
||||
},
|
||||
|
||||
// 钱包充值
|
||||
rechargeWallet: (params) => {
|
||||
return http.post('/wallets/recharge', params)
|
||||
},
|
||||
|
||||
// 钱包提现
|
||||
withdrawWallet: (params) => {
|
||||
return http.post('/wallets/withdraw', params)
|
||||
},
|
||||
|
||||
// 冻结钱包资金
|
||||
freezeWalletFunds: (params) => {
|
||||
return http.post('/wallets/freeze_funds', params)
|
||||
},
|
||||
|
||||
// 解冻钱包资金
|
||||
unfreezeWalletFunds: (params) => {
|
||||
return http.post('/wallets/unfreeze_funds', params)
|
||||
},
|
||||
|
||||
// 获取钱包交易记录
|
||||
getWalletTransactions: (params) => {
|
||||
return http.post('/wallets/transactions', params)
|
||||
},
|
||||
|
||||
// 重置钱包密码
|
||||
resetWalletPassword: (params) => {
|
||||
return http.post('/wallets/reset_password', params)
|
||||
},
|
||||
|
||||
// 获取钱包余额统计
|
||||
getWalletBalanceStats: (params) => {
|
||||
return http.post('/wallets/balance_stats', params)
|
||||
}
|
||||
}
|
||||
28
demo/src/api/order/withdraw_audit_server.js
Normal file
28
demo/src/api/order/withdraw_audit_server.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取提现审核列表
|
||||
getWithdrawAuditList: (params) => {
|
||||
return http.post('/wallet/withdraw_audit/list', params)
|
||||
},
|
||||
|
||||
// 审核提现申请
|
||||
auditWithdraw: (params) => {
|
||||
return http.post('/wallet/withdraw_audit/audit', params)
|
||||
},
|
||||
|
||||
// 批量审核提现申请
|
||||
batchAuditWithdraw: (params) => {
|
||||
return http.post('/wallet/withdraw_audit/batch_audit', params)
|
||||
},
|
||||
|
||||
// 获取提现详情
|
||||
getWithdrawDetail: (params) => {
|
||||
return http.get('/wallet/withdraw_audit/detail', params)
|
||||
},
|
||||
|
||||
// 获取提现统计
|
||||
getWithdrawStats: (params) => {
|
||||
return http.post('/wallet/withdraw_audit/stats', params)
|
||||
}
|
||||
}
|
||||
33
demo/src/api/resources/sys_file_server.js
Normal file
33
demo/src/api/resources/sys_file_server.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import request from '@/libs/http'
|
||||
|
||||
export const getList = (params) => {
|
||||
return request({
|
||||
url: '/sys_file/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export const add = (data) => {
|
||||
return request({
|
||||
url: '/sys_file',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const edit = (data) => {
|
||||
return request({
|
||||
url: '/sys_file',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const del = (params) => {
|
||||
return request({
|
||||
url: '/sys_file',
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
}
|
||||
57
demo/src/api/statistics/game_statistics_server.js
Normal file
57
demo/src/api/statistics/game_statistics_server.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
// 获取球局统计列表
|
||||
export const getList = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/game_statistics/list',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取球局统计详情
|
||||
export const getDetail = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/game_statistics/detail',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 添加球局统计
|
||||
export const add = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/game_statistics/add',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑球局统计
|
||||
export const edit = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/game_statistics/edit',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 删除球局统计
|
||||
export const del = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/game_statistics/del',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 导出球局统计
|
||||
export const exportData = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/game_statistics/export',
|
||||
method: 'post',
|
||||
data: params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
53
demo/src/api/statistics/resources_server.js
Normal file
53
demo/src/api/statistics/resources_server.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取资源列表
|
||||
getResourcesList: (params) => {
|
||||
return http.post('/resources/page', params)
|
||||
},
|
||||
|
||||
// 获取所有资源
|
||||
getAllResources: (params) => {
|
||||
return http.get('/resources/all', params)
|
||||
},
|
||||
|
||||
// 获取资源详情
|
||||
getResourceDetail: (params) => {
|
||||
return http.get('/resources/detail', params)
|
||||
},
|
||||
|
||||
// 新增资源
|
||||
addResource: (params) => {
|
||||
return http.post('/resources/add', params)
|
||||
},
|
||||
|
||||
// 更新资源
|
||||
updateResource: (params) => {
|
||||
return http.post('/resources/edit', params)
|
||||
},
|
||||
|
||||
// 删除资源
|
||||
deleteResource: (params) => {
|
||||
return http.post('/resources/del', params)
|
||||
},
|
||||
|
||||
// 批量删除资源
|
||||
batchDeleteResources: (params) => {
|
||||
return http.post('/resources/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出资源数据
|
||||
exportResources: (params) => {
|
||||
return http.post('/resources/export', params)
|
||||
},
|
||||
|
||||
// 上传资源
|
||||
uploadResource: (params) => {
|
||||
return http.post('/resources/upload', params)
|
||||
},
|
||||
|
||||
// 获取资源统计
|
||||
getResourceStats: (params) => {
|
||||
return http.get('/resources/stats', params)
|
||||
}
|
||||
}
|
||||
66
demo/src/api/statistics/revenue_statistics_server.js
Normal file
66
demo/src/api/statistics/revenue_statistics_server.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
// 获取营收统计列表
|
||||
export const getList = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/list',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取营收统计详情
|
||||
export const getDetail = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/detail',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取营收统计概览
|
||||
export const getOverview = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/overview',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 添加营收统计
|
||||
export const add = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/add',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑营收统计
|
||||
export const edit = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/edit',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 删除营收统计
|
||||
export const del = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/del',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 导出营收统计
|
||||
export const exportData = (params) => {
|
||||
return http.request({
|
||||
url: '/admin/revenue_statistics/export',
|
||||
method: 'post',
|
||||
data: params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
15
demo/src/api/system/fileServe.js
Normal file
15
demo/src/api/system/fileServe.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import http from "@/libs/http";
|
||||
class FileServe {
|
||||
async upload_oos_img(row) {
|
||||
let res = await http.postFormData("/sys_file/upload_oos_img", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async upload_Img(row) {
|
||||
let res = await http.postFormData("/file/upload_Img", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const fileServe = new FileServe();
|
||||
export default fileServe;
|
||||
51
demo/src/api/system/hot_city_qr_config_server.js
Normal file
51
demo/src/api/system/hot_city_qr_config_server.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import http from '@/libs/http';
|
||||
|
||||
/**
|
||||
* 热门城市二维码配置相关API
|
||||
*/
|
||||
|
||||
// 获取配置列表
|
||||
const getHotCityQrConfigList = (params) => {
|
||||
return http.get('/wch_hot_city_qr_config/list', { params });
|
||||
};
|
||||
|
||||
// 获取所有配置
|
||||
const getAllHotCityQrConfig = () => {
|
||||
return http.get('/wch_hot_city_qr_config/all');
|
||||
};
|
||||
|
||||
// 获取配置详情
|
||||
const getHotCityQrConfigDetail = (id) => {
|
||||
return http.get(`/wch_hot_city_qr_config/detail/${id}`);
|
||||
};
|
||||
|
||||
// 创建配置
|
||||
const createHotCityQrConfig = (data) => {
|
||||
return http.post('/wch_hot_city_qr_config/create', data);
|
||||
};
|
||||
|
||||
// 更新配置
|
||||
const updateHotCityQrConfig = (id, data) => {
|
||||
return http.post(`/wch_hot_city_qr_config/update/${id}`, data);
|
||||
};
|
||||
|
||||
// 删除配置
|
||||
const deleteHotCityQrConfig = (id) => {
|
||||
return http.post(`/wch_hot_city_qr_config/delete/${id}`);
|
||||
};
|
||||
|
||||
// 批量删除配置
|
||||
const batchDeleteHotCityQrConfig = (ids) => {
|
||||
return http.post('/wch_hot_city_qr_config/batch_delete', { ids });
|
||||
};
|
||||
|
||||
export default {
|
||||
getHotCityQrConfigList,
|
||||
getAllHotCityQrConfig,
|
||||
getHotCityQrConfigDetail,
|
||||
createHotCityQrConfig,
|
||||
updateHotCityQrConfig,
|
||||
deleteHotCityQrConfig,
|
||||
batchDeleteHotCityQrConfig
|
||||
};
|
||||
|
||||
38
demo/src/api/system/pla_account_server.js
Normal file
38
demo/src/api/system/pla_account_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取所有平台账户
|
||||
all(param) {
|
||||
return http.get('/pla_account/all', param)
|
||||
},
|
||||
|
||||
// 获取平台账户详情
|
||||
detail(param) {
|
||||
return http.get('/pla_account/detail', param)
|
||||
},
|
||||
|
||||
// 分页查询平台账户
|
||||
page(param) {
|
||||
return http.post('/pla_account/page', param)
|
||||
},
|
||||
|
||||
// 新增平台账户
|
||||
add(param) {
|
||||
return http.post('/pla_account/add', param)
|
||||
},
|
||||
|
||||
// 编辑平台账户
|
||||
edit(param) {
|
||||
return http.post('/pla_account/edit', param)
|
||||
},
|
||||
|
||||
// 删除平台账户
|
||||
del(param) {
|
||||
return http.post('/pla_account/del', param)
|
||||
},
|
||||
|
||||
// 导出平台账户数据
|
||||
exportCsv(param) {
|
||||
return http.post('/pla_account/export', param)
|
||||
}
|
||||
}
|
||||
30
demo/src/api/system/rolePermissionServer.js
Normal file
30
demo/src/api/system/rolePermissionServer.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import http from '@/libs/http'
|
||||
class RolePermissionServer {
|
||||
async getRoles(callback) {
|
||||
let res = await http.get('/SysRolePermission/Query', {})
|
||||
return res
|
||||
}
|
||||
|
||||
async getRole(row) {
|
||||
let res = await http.get('/SysRolePermission/QueryByRoleId', row)
|
||||
return res
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post('/SysRolePermission/add', row)
|
||||
return res
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post('/SysRolePermission/edit', row)
|
||||
return res
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post('/SysRolePermission/del', row)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
const rolePermissionServer = new RolePermissionServer()
|
||||
export default rolePermissionServer
|
||||
26
demo/src/api/system/roleServer.js
Normal file
26
demo/src/api/system/roleServer.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import http from "@/libs/http";
|
||||
class RoleServer {
|
||||
async list() {
|
||||
let res = await http.get("/sys_role/index", {});
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_role/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_role/edit", row);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_role/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const roleServer = new RoleServer();
|
||||
export default roleServer;
|
||||
15
demo/src/api/system/shpProfitServer.js
Normal file
15
demo/src/api/system/shpProfitServer.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import http from '@/libs/http'
|
||||
class ShpProfitServer {
|
||||
async report(param) {
|
||||
let res = await http.post('/shpProfit/report', param)
|
||||
return res
|
||||
}
|
||||
|
||||
async list(param) {
|
||||
let res = await http.post('/shpProfit/list', param)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
const shpProfitServer = new ShpProfitServer()
|
||||
export default shpProfitServer
|
||||
25
demo/src/api/system/specificationServer.js
Normal file
25
demo/src/api/system/specificationServer.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import http from '@/libs/http'
|
||||
class SpecificationServer {
|
||||
async list() {
|
||||
let res = await http.post('/specification/list', {})
|
||||
return res
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post('/specification/add', row)
|
||||
return res
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post('/specification/edit', row)
|
||||
return res
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post('/specification/del', row)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
const specificationServer = new SpecificationServer()
|
||||
export default specificationServer
|
||||
10
demo/src/api/system/sysAddressServer.js
Normal file
10
demo/src/api/system/sysAddressServer.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import http from "@/libs/http";
|
||||
class SysAddress {
|
||||
async index(param) {
|
||||
let res = await http.get("/sys_address/index", param);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const sysAddress = new SysAddress();
|
||||
export default sysAddress;
|
||||
30
demo/src/api/system/sysModuleServer.js
Normal file
30
demo/src/api/system/sysModuleServer.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import http from "@/libs/http";
|
||||
class SysModuleServer {
|
||||
async all() {
|
||||
let res = await http.get("/sys_menu/all", {});
|
||||
return res;
|
||||
}
|
||||
|
||||
async list(row) {
|
||||
let res = await http.get("/sys_menu/all", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_menu/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_menu/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_menu/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const sysModuleServer = new SysModuleServer();
|
||||
export default sysModuleServer;
|
||||
30
demo/src/api/system/sys_log_serve.js
Normal file
30
demo/src/api/system/sys_log_serve.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import http from "@/libs/http";
|
||||
class SysLogServe {
|
||||
async all(param) {
|
||||
let res = await http.get("/sys_log/all", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async detail(param) {
|
||||
let res = await http.get("/sys_log/detail", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async delete(param) {
|
||||
let res = await http.get("/sys_log/delete", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async delete_all(param) {
|
||||
let res = await http.get("/sys_log/delete_all", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async operates(param) {
|
||||
let res = await http.get("/sys_log/operates", param);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const sys_log_serve = new SysLogServe();
|
||||
export default sys_log_serve;
|
||||
38
demo/src/api/system/systemType_server.js
Normal file
38
demo/src/api/system/systemType_server.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import http from '@/libs/http';
|
||||
class systemTypeClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/sys_project_type/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/sys_project_type/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/sys_project_type/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/sys_project_type/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/sys_project_type/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/sys_project_type/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const systemTypeServer = new systemTypeClServer();
|
||||
export default systemTypeServer;
|
||||
|
||||
31
demo/src/api/system/tableServer.js
Normal file
31
demo/src/api/system/tableServer.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import http from '@/libs/http'
|
||||
class TableServer {
|
||||
async getAll(callback) {
|
||||
return await http.get('/table/index', {})
|
||||
}
|
||||
|
||||
async add(row, callback) {
|
||||
return await http.post('/table/add', row)
|
||||
}
|
||||
|
||||
async edit(row, callback) {
|
||||
return await http.post('/table/edit', row, function(res) {
|
||||
callback && callback(res)
|
||||
})
|
||||
}
|
||||
|
||||
async del(row, callback) {
|
||||
return await http.post('/table/del', row)
|
||||
}
|
||||
|
||||
async autoApi(id) {
|
||||
return await http.get('/template/api', { id: id })
|
||||
}
|
||||
|
||||
async autoDb(id) {
|
||||
return await http.get('/template/autoDb', { id: id })
|
||||
}
|
||||
}
|
||||
|
||||
const tableServer = new TableServer()
|
||||
export default tableServer
|
||||
40
demo/src/api/system/userServer.js
Normal file
40
demo/src/api/system/userServer.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import http from "@/libs/http";
|
||||
class UserServer {
|
||||
async login(row) {
|
||||
let res = await http.post("/sys_user/login", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async all() {
|
||||
let res = await http.get("/sys_user/index", {});
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/sys_user/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async authorityMenus() {
|
||||
let res = await http.post("/sys_user/authorityMenus", {});
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_user/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_user/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_user/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const userServer = new UserServer();
|
||||
export default userServer;
|
||||
33
demo/src/api/system/wch_professions_server.js
Normal file
33
demo/src/api/system/wch_professions_server.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取职业列表
|
||||
page: (params) => {
|
||||
return http.post('/wch_professions/page', params)
|
||||
},
|
||||
|
||||
// 获取所有职业
|
||||
all: (params) => {
|
||||
return http.post('/wch_professions/all', params)
|
||||
},
|
||||
|
||||
// 新增职业
|
||||
add: (params) => {
|
||||
return http.post('/wch_professions/add', params)
|
||||
},
|
||||
|
||||
// 更新职业
|
||||
edit: (params) => {
|
||||
return http.post('/wch_professions/edit', params)
|
||||
},
|
||||
|
||||
// 删除职业
|
||||
del: (params) => {
|
||||
return http.post('/wch_professions/del', params)
|
||||
},
|
||||
|
||||
// 导出职业数据
|
||||
exportCsv: (params) => {
|
||||
return http.post('/wch_professions/exportCsv', params)
|
||||
}
|
||||
}
|
||||
30
demo/src/api/system_high/formFieldServer.js
Normal file
30
demo/src/api/system_high/formFieldServer.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import http from "@/libs/http";
|
||||
class FormFieldServer {
|
||||
async all(param) {
|
||||
let res = await http.get("/sys_form_field/all", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res = await http.post("/sys_form_field/page", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_form_field/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_form_field/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_form_field/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const formFieldServer = new FormFieldServer();
|
||||
export default formFieldServer;
|
||||
35
demo/src/api/system_high/formServer.js
Normal file
35
demo/src/api/system_high/formServer.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from "@/libs/http";
|
||||
class FormServer {
|
||||
async all(param) {
|
||||
let res = await http.get("/sys_form/all", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res = await http.post("/sys_form/page", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async generate(row) {
|
||||
let res = await http.post("/sys_form/generate", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_form/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_form/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_form/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const formServer = new FormServer();
|
||||
export default formServer;
|
||||
49
demo/src/api/system_high/menuServer.js
Normal file
49
demo/src/api/system_high/menuServer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import http from "@/libs/http";
|
||||
|
||||
class MenuServer {
|
||||
async list(row) {
|
||||
let res = await http.get("/sys_menu/index", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async generate(row) {
|
||||
let res = await http.post("/sys_menu/generate", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_menu/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_menu/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_menu/del", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async generate(row) {
|
||||
let res = await http.post("/form/generate", row);
|
||||
return res;
|
||||
}
|
||||
async generateModel(row) {
|
||||
let res = await http.post("/model/generate", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async modelAll(row) {
|
||||
let res = await http.post("/model/all", row);
|
||||
return res;
|
||||
}
|
||||
async modelInterface(row) {
|
||||
let res = await http.post("/model/interface", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
const menuServer = new MenuServer();
|
||||
export default menuServer;
|
||||
32
demo/src/api/system_high/modelFieldServer.js
Normal file
32
demo/src/api/system_high/modelFieldServer.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import http from "@/libs/http";
|
||||
class ModelFieldServer {
|
||||
async all(row) {
|
||||
let res = await http.get("/sys_model_field/all", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async allByKey(row) {
|
||||
let res = await http.get("/sys_model_field/allByKey", row, {
|
||||
hideLoad: true
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_model_field/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_model_field/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_model_field/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const modelFieldServer = new ModelFieldServer();
|
||||
export default modelFieldServer;
|
||||
40
demo/src/api/system_high/modelServer.js
Normal file
40
demo/src/api/system_high/modelServer.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import http from "@/libs/http";
|
||||
class ModelServer {
|
||||
async interface(row) {
|
||||
let res = await http.post("/sys_model/interface", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async all() {
|
||||
let res = await http.get("/sys_model/all", {});
|
||||
return res;
|
||||
}
|
||||
|
||||
async detail(row) {
|
||||
let res = await http.get("/sys_model/detail", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async regenerate(row) {
|
||||
let res = await http.post("/sys_model/regenerate", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res = await http.post("/sys_model/add", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res = await http.post("/sys_model/edit", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res = await http.post("/sys_model/del", row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const modelServer = new ModelServer();
|
||||
export default modelServer;
|
||||
29
demo/src/api/system_high/paramSetupServer.js
Normal file
29
demo/src/api/system_high/paramSetupServer.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import http from "@/libs/http";
|
||||
class ParamSetupServer {
|
||||
async getAll() {
|
||||
return await http.get("/sys_parameter/index", {});
|
||||
}
|
||||
|
||||
async getOne(key) {
|
||||
return await http.get("/sys_parameter/key", { key });
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
return await http.post("/sys_parameter/add", row);
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
return await http.post("/sys_parameter/edit", row);
|
||||
}
|
||||
|
||||
async setSysConfig(row) {
|
||||
return await http.post("/sys_parameter/setSysConfig", row);
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
return await http.post("/sys_parameter/del", row);
|
||||
}
|
||||
}
|
||||
|
||||
const paramSetupServer = new ParamSetupServer();
|
||||
export default paramSetupServer;
|
||||
29
demo/src/api/system_high/sysControlTypeServer.js
Normal file
29
demo/src/api/system_high/sysControlTypeServer.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import http from "@/libs/http";
|
||||
class SysControlTypeServer {
|
||||
async all(param) {
|
||||
let res = await http.get("/sys_control_type/all", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res = await http.post("/sys_control_type/page", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(param) {
|
||||
let res = await http.post("/sys_control_type/add", param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(param) {
|
||||
let res = await http.post("/sys_control_type/edit", param);
|
||||
return res;
|
||||
}
|
||||
async del(param) {
|
||||
let res = await http.post("/sys_control_type/del", param);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const sysControlTypeServer = new SysControlTypeServer();
|
||||
export default sysControlTypeServer;
|
||||
35
demo/src/api/users/recommend_blocks_server.js
Normal file
35
demo/src/api/users/recommend_blocks_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class recommend_blocksClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/recommend_blocks/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/recommend_blocks/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/recommend_blocks/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/recommend_blocks/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/recommend_blocks/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/recommend_blocks/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const recommend_blocksServer = new recommend_blocksClServer();
|
||||
export default recommend_blocksServer;
|
||||
35
demo/src/api/users/user_follows_server.js
Normal file
35
demo/src/api/users/user_follows_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class user_followsClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/user_follows/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/user_follows/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/user_follows/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/user_follows/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/user_follows/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/user_follows/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const user_followsServer = new user_followsClServer();
|
||||
export default user_followsServer;
|
||||
35
demo/src/api/users/user_tracking_server.js
Normal file
35
demo/src/api/users/user_tracking_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class user_trackingClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/user_tracking/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/user_tracking/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/user_tracking/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/user_tracking/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/user_tracking/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/user_tracking/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const user_trackingServer = new user_trackingClServer();
|
||||
export default user_trackingServer;
|
||||
53
demo/src/api/users/wch_cities_server.js
Normal file
53
demo/src/api/users/wch_cities_server.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import http from '@/libs/http'
|
||||
|
||||
export default {
|
||||
// 获取城市列表
|
||||
getCitiesList: (params) => {
|
||||
return http.post('/wch_cities/page', params)
|
||||
},
|
||||
|
||||
// 获取所有城市
|
||||
getAllCities: (params) => {
|
||||
return http.get('/wch_cities/all', params)
|
||||
},
|
||||
|
||||
// 获取城市详情
|
||||
getCityDetail: (params) => {
|
||||
return http.get('/wch_cities/detail', params)
|
||||
},
|
||||
|
||||
// 新增城市
|
||||
addCity: (params) => {
|
||||
return http.post('/wch_cities/add', params)
|
||||
},
|
||||
|
||||
// 更新城市
|
||||
updateCity: (params) => {
|
||||
return http.post('/wch_cities/edit', params)
|
||||
},
|
||||
|
||||
// 删除城市
|
||||
deleteCity: (params) => {
|
||||
return http.post('/wch_cities/del', params)
|
||||
},
|
||||
|
||||
// 批量删除城市
|
||||
batchDeleteCities: (params) => {
|
||||
return http.post('/wch_cities/batch_delete', params)
|
||||
},
|
||||
|
||||
// 导出城市数据
|
||||
exportCities: (params) => {
|
||||
return http.post('/wch_cities/export', params)
|
||||
},
|
||||
|
||||
// 获取热门城市
|
||||
getHotCities: (params) => {
|
||||
return http.get('/wch_cities/hot', params)
|
||||
},
|
||||
|
||||
// 设置热门城市
|
||||
setHotCities: (params) => {
|
||||
return http.post('/wch_cities/set_hot', params)
|
||||
}
|
||||
}
|
||||
35
demo/src/api/venues/wch_cities_server.js
Normal file
35
demo/src/api/venues/wch_cities_server.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import http from '@/libs/http';
|
||||
class wch_citiesClServer {
|
||||
async all(param) {
|
||||
let res= await http.get('/wch_cities/all', param);
|
||||
return res;
|
||||
}
|
||||
|
||||
async page(row) {
|
||||
let res= await http.post('/wch_cities/page', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async exportCsv(row) {
|
||||
let res = http.fileExport("/wch_cities/export", row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async add(row) {
|
||||
let res= await http.post('/wch_cities/add', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async edit(row) {
|
||||
let res= await http.post('/wch_cities/edit', row);
|
||||
return res;
|
||||
}
|
||||
|
||||
async del(row) {
|
||||
let res= await http.post('/wch_cities/del', row);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
const wch_citiesServer = new wch_citiesClServer();
|
||||
export default wch_citiesServer;
|
||||
171
demo/src/components/CustomPage.vue
Normal file
171
demo/src/components/CustomPage.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div style="padding: 20px;">
|
||||
<Card>
|
||||
<p slot="title">
|
||||
<Icon type="ios-cube" />
|
||||
自定义页面示例
|
||||
</p>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<Alert type="success" show-icon>
|
||||
这是一个自定义页面组件示例,展示如何在 Admin Framework 中添加自定义页面。
|
||||
</Alert>
|
||||
</div>
|
||||
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<Card title="基本信息" style="margin-bottom: 16px;">
|
||||
<p><strong>当前时间:</strong> {{ currentTime }}</p>
|
||||
<p><strong>页面路径:</strong> {{ $route.path }}</p>
|
||||
<p><strong>框架版本:</strong> {{ framework.version }}</p>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col span="12">
|
||||
<Card title="Vuex 状态" style="margin-bottom: 16px;">
|
||||
<p><strong>自定义数据:</strong> {{ customData }}</p>
|
||||
<p><strong>计数器:</strong> {{ count }}</p>
|
||||
<div style="margin-top: 10px;">
|
||||
<Button type="primary" @click="handleIncrement">增加计数</Button>
|
||||
<Button type="default" @click="handleIncrementAsync" style="margin-left: 8px;">
|
||||
异步增加
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Card title="API 测试" style="margin-bottom: 16px;">
|
||||
<Form :label-width="80">
|
||||
<FormItem label="请求地址">
|
||||
<Input v-model="apiUrl" placeholder="输入 API 地址" />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="handleApiTest" :loading="apiLoading">
|
||||
发送请求
|
||||
</Button>
|
||||
<Button @click="handleClear" style="margin-left: 8px;">清空结果</Button>
|
||||
</FormItem>
|
||||
<FormItem label="响应结果" v-if="apiResult">
|
||||
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px;">{{ apiResult }}</pre>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card title="UI 工具测试">
|
||||
<Button type="success" @click="showSuccess">成功提示</Button>
|
||||
<Button type="warning" @click="showWarning" style="margin-left: 8px;">警告提示</Button>
|
||||
<Button type="error" @click="showError" style="margin-left: 8px;">错误提示</Button>
|
||||
<Button type="info" @click="showConfirm" style="margin-left: 8px;">确认对话框</Button>
|
||||
</Card>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'CustomPage',
|
||||
data() {
|
||||
return {
|
||||
currentTime: new Date().toLocaleString(),
|
||||
timer: null,
|
||||
apiUrl: '/api/test',
|
||||
apiLoading: false,
|
||||
apiResult: null,
|
||||
framework: window.framework
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('custom', ['customData', 'count'])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('custom', ['INCREMENT']),
|
||||
...mapActions('custom', ['incrementAsync', 'updateCustomData']),
|
||||
|
||||
// 增加计数
|
||||
handleIncrement() {
|
||||
this.INCREMENT()
|
||||
this.$Message.success('计数已增加')
|
||||
},
|
||||
|
||||
// 异步增加
|
||||
handleIncrementAsync() {
|
||||
this.$Message.info('1秒后增加计数...')
|
||||
this.incrementAsync()
|
||||
},
|
||||
|
||||
// API 测试
|
||||
async handleApiTest() {
|
||||
this.apiLoading = true
|
||||
this.apiResult = null
|
||||
|
||||
try {
|
||||
const response = await this.$http.get(this.apiUrl)
|
||||
this.apiResult = JSON.stringify(response.data, null, 2)
|
||||
this.$Message.success('请求成功')
|
||||
} catch (error) {
|
||||
this.apiResult = JSON.stringify({
|
||||
error: error.message,
|
||||
details: error.toString()
|
||||
}, null, 2)
|
||||
this.$Message.error('请求失败: ' + error.message)
|
||||
} finally {
|
||||
this.apiLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 清空结果
|
||||
handleClear() {
|
||||
this.apiResult = null
|
||||
},
|
||||
|
||||
// UI 工具测试
|
||||
showSuccess() {
|
||||
this.$uiTool.success('这是一个成功提示')
|
||||
},
|
||||
|
||||
showWarning() {
|
||||
this.$uiTool.warning('这是一个警告提示')
|
||||
},
|
||||
|
||||
showError() {
|
||||
this.$uiTool.error('这是一个错误提示')
|
||||
},
|
||||
|
||||
showConfirm() {
|
||||
this.$uiTool.confirm('确定要执行此操作吗?').then(() => {
|
||||
this.$Message.success('已确认')
|
||||
}).catch(() => {
|
||||
this.$Message.info('已取消')
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 定时更新时间
|
||||
this.timer = setInterval(() => {
|
||||
this.currentTime = new Date().toLocaleString()
|
||||
}, 1000)
|
||||
|
||||
console.log('CustomPage 组件已挂载')
|
||||
console.log('可用的工具函数:', this.$tools)
|
||||
console.log('可用的 UI 工具:', this.$uiTool)
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
pre {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
0
demo/src/libs/funTool.js
Normal file
0
demo/src/libs/funTool.js
Normal file
0
demo/src/libs/http.js
Normal file
0
demo/src/libs/http.js
Normal file
0
demo/src/libs/uiTool.js
Normal file
0
demo/src/libs/uiTool.js
Normal file
59
demo/src/main.js
Normal file
59
demo/src/main.js
Normal file
@@ -0,0 +1,59 @@
|
||||
// 引入依赖
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import Vuex from 'vuex'
|
||||
import ViewUI from 'view-design'
|
||||
import axios from 'axios'
|
||||
|
||||
// 引入样式
|
||||
import 'view-design/dist/styles/iview.css'
|
||||
|
||||
// 引入 Admin Framework(使用本地构建的文件)
|
||||
import AdminFramework from '../../dist/admin-framework.js'
|
||||
|
||||
// 引入组件映射表
|
||||
import componentMap from './router/component-map.js'
|
||||
|
||||
// 使用插件
|
||||
Vue.use(ViewUI)
|
||||
|
||||
// 配置参数
|
||||
const config = {
|
||||
title: 'Admin Framework Demo',
|
||||
apiUrl: 'http://localhost:9098/admin_api/', // 修改为你的 API 地址
|
||||
uploadUrl: 'http://localhost:9098/admin_api/upload' // 修改为你的上传地址
|
||||
}
|
||||
|
||||
// 初始化框架
|
||||
AdminFramework.install(Vue, {
|
||||
config: config,
|
||||
ViewUI: ViewUI,
|
||||
VueRouter: VueRouter,
|
||||
Vuex: Vuex,
|
||||
createPersistedState: null,
|
||||
componentMap: componentMap // 传入组件映射表,用于动态路由
|
||||
})
|
||||
|
||||
// 创建 Vue 实例
|
||||
const app = new Vue({
|
||||
router: AdminFramework.router,
|
||||
store: AdminFramework.store,
|
||||
render: h => h('router-view'),
|
||||
created() {
|
||||
console.log('=== Admin Framework Demo 启动成功 ===')
|
||||
console.log('框架版本:', AdminFramework.version)
|
||||
console.log('配置信息:', this.$config)
|
||||
}
|
||||
})
|
||||
|
||||
// 挂载应用
|
||||
app.$mount('#app')
|
||||
|
||||
// 全局暴露(方便调试)
|
||||
window.app = app
|
||||
window.rootVue = app
|
||||
window.framework = AdminFramework
|
||||
|
||||
// 提示信息
|
||||
ViewUI.Message.success('Admin Framework Demo 启动成功!')
|
||||
|
||||
108
demo/src/router/component-map.js
Normal file
108
demo/src/router/component-map.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// 组件映射表 - 将后端返回的组件路径映射到实际的 Vue 组件
|
||||
// 后端返回的 component 字段需要与这里的 key 对应
|
||||
|
||||
// ========== AI 模块 ==========
|
||||
import AiMessages from '../views/ai/ai_messages.vue'
|
||||
|
||||
// ========== 球场模块 ==========
|
||||
import GameComments from '../views/ball/game_comments.vue'
|
||||
import GameParticipants from '../views/ball/game_participants.vue'
|
||||
import Games from '../views/ball/games.vue'
|
||||
import Venues from '../views/ball/venues.vue'
|
||||
import WchUsers from '../views/ball/wch_users.vue'
|
||||
|
||||
// ========== 业务模块 ==========
|
||||
import HotCityQr from '../views/business/hot_city_qr.vue'
|
||||
|
||||
// ========== 消息模块 ==========
|
||||
import MsgNotifications from '../views/message/msg_notifications.vue'
|
||||
|
||||
// ========== NTRP 模块 ==========
|
||||
import NtrQuestions from '../views/ntrp/ntr_questions.vue'
|
||||
import NtrRecords from '../views/ntrp/ntr_records.vue'
|
||||
|
||||
// ========== 订单模块 ==========
|
||||
import FrozenFunds from '../views/order/frozen_funds.vue'
|
||||
import PayOrders from '../views/order/pay_orders.vue'
|
||||
import TransferDetails from '../views/order/transfer_details.vue'
|
||||
import WalletTransactions from '../views/order/wallet_transactions.vue'
|
||||
import WchWallets from '../views/order/wch_wallets.vue'
|
||||
|
||||
// ========== 统计模块 ==========
|
||||
import Resources from '../views/statistics/resources.vue'
|
||||
|
||||
// ========== 用户模块 ==========
|
||||
import RecommendBlocks from '../views/users/recommend_blocks.vue'
|
||||
import UserFollows from '../views/users/user_follows.vue'
|
||||
import UserTracking from '../views/users/user_tracking.vue'
|
||||
|
||||
// ========== 自定义组件 ==========
|
||||
import CustomPage from '../components/CustomPage.vue'
|
||||
|
||||
/**
|
||||
* 组件映射对象
|
||||
* key: 后端返回的组件路径(去掉 .vue 后缀或保留都可以)
|
||||
* value: 实际的 Vue 组件
|
||||
*/
|
||||
const componentMap = {
|
||||
// ===== AI 模块 =====
|
||||
'ai/ai_messages': AiMessages,
|
||||
'ai/ai_messages.vue': AiMessages,
|
||||
|
||||
// ===== 球场模块 =====
|
||||
'ball/game_comments': GameComments,
|
||||
'ball/game_comments.vue': GameComments,
|
||||
'ball/game_participants': GameParticipants,
|
||||
'ball/game_participants.vue': GameParticipants,
|
||||
'ball/games': Games,
|
||||
'ball/games.vue': Games,
|
||||
'ball/venues': Venues,
|
||||
'ball/venues.vue': Venues,
|
||||
'ball/wch_users': WchUsers,
|
||||
'ball/wch_users.vue': WchUsers,
|
||||
|
||||
// ===== 业务模块 =====
|
||||
'business/hot_city_qr': HotCityQr,
|
||||
'business/hot_city_qr.vue': HotCityQr,
|
||||
|
||||
// ===== 消息模块 =====
|
||||
'message/msg_notifications': MsgNotifications,
|
||||
'message/msg_notifications.vue': MsgNotifications,
|
||||
|
||||
// ===== NTRP 模块 =====
|
||||
'ntrp/ntr_questions': NtrQuestions,
|
||||
'ntrp/ntr_questions.vue': NtrQuestions,
|
||||
'ntrp/ntr_records': NtrRecords,
|
||||
'ntrp/ntr_records.vue': NtrRecords,
|
||||
|
||||
// ===== 订单模块 =====
|
||||
'order/frozen_funds': FrozenFunds,
|
||||
'order/frozen_funds.vue': FrozenFunds,
|
||||
'order/pay_orders': PayOrders,
|
||||
'order/pay_orders.vue': PayOrders,
|
||||
'order/transfer_details': TransferDetails,
|
||||
'order/transfer_details.vue': TransferDetails,
|
||||
'order/wallet_transactions': WalletTransactions,
|
||||
'order/wallet_transactions.vue': WalletTransactions,
|
||||
'order/wch_wallets': WchWallets,
|
||||
'order/wch_wallets.vue': WchWallets,
|
||||
|
||||
// ===== 统计模块 =====
|
||||
'statistics/resources': Resources,
|
||||
'statistics/resources.vue': Resources,
|
||||
|
||||
// ===== 用户模块 =====
|
||||
'users/recommend_blocks': RecommendBlocks,
|
||||
'users/recommend_blocks.vue': RecommendBlocks,
|
||||
'users/user_follows': UserFollows,
|
||||
'users/user_follows.vue': UserFollows,
|
||||
'users/user_tracking': UserTracking,
|
||||
'users/user_tracking.vue': UserTracking,
|
||||
|
||||
// ===== 自定义组件 =====
|
||||
'custom/page': CustomPage,
|
||||
'custom/page.vue': CustomPage
|
||||
}
|
||||
|
||||
export default componentMap
|
||||
|
||||
169
demo/src/views/ai/ai_messages.vue
Normal file
169
demo/src/views/ai/ai_messages.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="消息类型">
|
||||
<Select v-model="gridOption.param.seachOption.message_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="question">提问</Option>
|
||||
<Option value="feedback">反馈</Option>
|
||||
<Option value="suggestion">建议</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="处理状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="pending">待处理</Option>
|
||||
<Option value="processing">处理中</Option>
|
||||
<Option value="completed">已完成</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import ai_messagesServer from '@/api/ai/ai_messages_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["user_id"] = [{ required: true, type: "number", message: '请填写用户ID', trigger: 'change' }];
|
||||
rules["message_type"] = [{ required: true, message: '请填写消息类型' }];
|
||||
rules["content"] = [{ required: true, message: '请填写消息内容' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'nickname', value: '用户昵称' }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
message_type: null,
|
||||
status: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '用户ID', key: 'user_id', minWidth: 120 },
|
||||
{ title: '用户昵称', key: 'nickname', minWidth: 120 },
|
||||
{ title: '消息类型', key: 'message_type', minWidth: 120 },
|
||||
{ title: '消息内容', key: 'content', minWidth: 300 },
|
||||
{ title: 'AI回复', key: 'ai_response', minWidth: 300 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 150 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '用户ID', key: 'user_id', type: 'number', required: true },
|
||||
{ title: '消息类型', key: 'message_type', type: 'text', required: true },
|
||||
{ title: '消息内容', key: 'content', type: 'textarea', required: true },
|
||||
{ title: 'AI回复', key: 'ai_response', type: 'textarea' },
|
||||
{ title: '处理状态', key: 'status', type: 'select', options: [
|
||||
{ value: 'pending', label: '待处理' },
|
||||
{ value: 'processing', label: '处理中' },
|
||||
{ value: 'completed', label: '已完成' },
|
||||
{ value: 'failed', label: '处理失败' }
|
||||
]}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
ai_messagesServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await ai_messagesServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
exportCsv() {
|
||||
ai_messagesServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, 'AI消息管理.csv');
|
||||
});
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
message_type: null,
|
||||
status: null
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
161
demo/src/views/ball/game_comments.vue
Normal file
161
demo/src/views/ball/game_comments.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="active">正常</Option>
|
||||
<Option value="hidden">隐藏</Option>
|
||||
<Option value="deleted">已删除</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import game_commentsServer from '@/api/ball/game_comments_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["game_id"] = [{ required: true, type: "number", message: '请填写球局ID', trigger: 'change' }];
|
||||
rules["user_id"] = [{ required: true, type: "number", message: '请填写用户ID', trigger: 'change' }];
|
||||
rules["content"] = [{ required: true, message: '请填写评论内容' }];
|
||||
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: 'game_id', value: '球局ID' },
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'content', value: '评论内容' }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'content',
|
||||
value: '',
|
||||
status: null // 状态筛选
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '球局ID', key: 'game_id', minWidth: 120 },
|
||||
{ title: '用户ID', key: 'user_id', minWidth: 120 },
|
||||
{ title: '用户昵称', key: 'nickname', minWidth: 120 },
|
||||
{ title: '评论内容', key: 'content', minWidth: 300 },
|
||||
{ title: '点赞数', key: 'like_count', minWidth: 120 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 150 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '球局ID', key: 'game_id', type: 'number', required: true },
|
||||
{ title: '用户ID', key: 'user_id', type: 'number', required: true },
|
||||
{ title: '评论内容', key: 'content', type: 'textarea', required: true },
|
||||
{ title: '点赞数', key: 'like_count', type: 'number' },
|
||||
{ title: '状态', key: 'status', type: 'select', options: [
|
||||
{ value: 'active', label: '正常' },
|
||||
{ value: 'hidden', label: '隐藏' },
|
||||
{ value: 'deleted', label: '已删除' }
|
||||
]}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
game_commentsServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await game_commentsServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'content',
|
||||
value: '',
|
||||
status: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
exportCsv() {
|
||||
game_commentsServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '球局评论.csv');
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
314
demo/src/views/ball/game_participants.vue
Normal file
314
demo/src/views/ball/game_participants.vue
Normal file
@@ -0,0 +1,314 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px" :placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="参与状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="joined">已加入</Option>
|
||||
<Option value="cancelled">已取消</Option>
|
||||
<Option value="substitute">替补</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="付款状态">
|
||||
<Select v-model="gridOption.param.seachOption.payment_status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="pending">待支付</Option>
|
||||
<Option value="paid">已支付</Option>
|
||||
<Option value="refunded">已退款</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import menuServer from '@/api/system_high/menuServer.js'
|
||||
import gameParticipantsServer from '@/api/ball/game_participants_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["id"] = [{ required: true, message: '请填写ID' }];
|
||||
rules["game_id"] = [{ required: true, type: "number", message: '请输入球局ID', trigger: 'change' }];
|
||||
rules["user_id"] = [{ required: true, message: '请填写参与用户ID' }];
|
||||
rules["status"] = [{ required: true, message: '请选择参与状态' }];
|
||||
rules["payment_status"] = [{ required: true, message: '请选择付款状态' }];
|
||||
rules["price"] = [{ required: false, type: "number", message: '请输入价格(元)', trigger: 'change' }];
|
||||
rules["payment_order_id"] = [{ required: false, message: '请填写支付订单ID' }];
|
||||
rules["join_message"] = [{ required: false, message: '请填写加入留言' }];
|
||||
rules["skill_level"] = [{ required: false, type: "number", message: '请输入技能水平(NTRP)', trigger: 'change' }];
|
||||
rules["contact_info"] = [{ required: false, message: '请填写联系方式' }];
|
||||
rules["joined_at"] = [{ required: true, message: '请选择加入时间' }];
|
||||
rules["cancelled_at"] = [{ required: false, message: '请选择取消时间' }];
|
||||
rules["cancel_reason"] = [{ required: false, message: '请填写取消原因' }];
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: "game_id", value: "球局ID" },
|
||||
{ key: "user_id", value: "用户ID" },
|
||||
{ key: "join_message", value: "加入留言" }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: "game_id",
|
||||
value: "",
|
||||
status: null, // 参与状态筛选
|
||||
payment_status: null // 付款状态筛选
|
||||
},
|
||||
pageOption: {
|
||||
total: 0,
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
rules,
|
||||
columns: [
|
||||
{ key: 'id', title: 'ID', minWidth: 80, is_show_edit: 0 },
|
||||
|
||||
{ key: "id", title: "ID", disabled: true, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{
|
||||
key: "game_id",
|
||||
title: "球局",
|
||||
disabled: true,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
data_type: "number",
|
||||
com: "InputNumber",
|
||||
render: (h, params) => {
|
||||
const game = params.row.gme_game;
|
||||
if (game) {
|
||||
return h('span', { attrs: { title: game.title } }, `#${game.id} ${game.title.substring(0, 10)}...`);
|
||||
}
|
||||
return h('span', `#${params.row.game_id}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "user_id",
|
||||
title: "用户",
|
||||
disabled: true,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Input",
|
||||
render: (h, params) => {
|
||||
const user = params.row.wch_user;
|
||||
if (user) {
|
||||
return h('span', { attrs: { title: `${user.nickname} (${user.phone})` } }, user.nickname);
|
||||
}
|
||||
return h('span', `用户#${params.row.user_id}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "status",
|
||||
title: "参与状态",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "joined", label: "已加入" },
|
||||
{ value: "cancelled", label: "已取消" },
|
||||
{ value: "substitute", label: "替补" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const statusMap = {
|
||||
'joined': { text: '已加入', color: 'green' },
|
||||
'cancelled': { text: '已取消', color: 'red' },
|
||||
'substitute': { text: '替补', color: 'orange' }
|
||||
};
|
||||
const status = statusMap[params.row.status] || { text: params.row.status || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: status.color } }, status.text);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "payment_status", title: "付款状态", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Select", options: [
|
||||
{ value: "pending", label: "待支付" },
|
||||
{ value: "paid", label: "已支付" },
|
||||
{ value: "refunded", label: "已退款" }
|
||||
]
|
||||
},
|
||||
{ key: "price", title: "价格(元)", disabled: false, is_show_edit: 1, is_show_list: 0, data_type: "number", com: "InputNumber" },
|
||||
{ key: "payment_order_id", title: "支付订单ID", disabled: true, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "join_message", title: "加入留言", disabled: false, is_show_edit: 1, is_show_list: 0, com: "TextArea" },
|
||||
{
|
||||
key: "skill_level",
|
||||
title: "技能水平",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
data_type: "number",
|
||||
com: "InputNumber",
|
||||
min: 0,
|
||||
max: 7,
|
||||
step: 0.1,
|
||||
render: (h, params) => {
|
||||
const level = params.row.skill_level;
|
||||
if (level === null || level === undefined || level === 0) {
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '未设置');
|
||||
}
|
||||
return h('Tag', { props: { color: 'blue' } }, `NTRP ${level}`);
|
||||
}
|
||||
},
|
||||
{ key: "contact_info", title: "联系方式", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "joined_at", title: "加入时间", disabled: true, is_show_edit: 1, is_show_list: 1, com: "DatePicker" },
|
||||
{ key: "cancelled_at", title: "取消时间", disabled: false, is_show_edit: 1, is_show_list: 0, com: "DatePicker" },
|
||||
{ key: "cancel_reason", title: "取消原因", disabled: false, is_show_edit: 1, is_show_list: 0, com: "TextArea" },
|
||||
{ key: 'create_time', title: '创建时间', minWidth: 150, is_show_edit: 0 },
|
||||
{ key: 'last_modify_time', title: '更新时间', minWidth: 150, is_show_edit: 0 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
is_show_list: 1,
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '查看',
|
||||
type: 'info',
|
||||
click: () => {
|
||||
this.showViewWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '修改',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
},],
|
||||
data: []
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
},
|
||||
editColumns() {
|
||||
let editTempColumns = this.gridOption.columns.filter(p => p.is_show_edit === 1)
|
||||
return editTempColumns
|
||||
},
|
||||
listColumns() {
|
||||
let listTempColumns = this.gridOption.columns.filter(p => p.is_show_list === 1)
|
||||
return listTempColumns
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.initCol()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.query(1)
|
||||
},
|
||||
async initCol() {
|
||||
|
||||
let columnRows = []
|
||||
let columnKeys = columnRows.map(p => p.key)
|
||||
let newColumns = this.gridOption.columns.filter(p => columnKeys.indexOf(p.key) > -1)
|
||||
for (let i = 0; i < newColumns.length; i++) {
|
||||
let curColumn = newColumns[i]
|
||||
let modelMap = columnRows[i].map_option
|
||||
let res = await menuServer.modelInterface({ model_key: columnRows[i].modelKey, map_option: modelMap })
|
||||
curColumn.source = res.data
|
||||
}
|
||||
|
||||
},
|
||||
async inquiry() {
|
||||
let res = await gameParticipantsServer.all(this.gridOption.param)
|
||||
this.gridOption.data = res.data
|
||||
},
|
||||
async query(page) {
|
||||
if (page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
}
|
||||
let res = await gameParticipantsServer.page(this.gridOption.param)
|
||||
this.gridOption.data = res.data.rows
|
||||
this.gridOption.param.pageOption.total = res.data.count
|
||||
},
|
||||
async showAddWarp() {
|
||||
this.$refs.editModal.addShow({
|
||||
'status': 'joined',
|
||||
'payment_status': 'pending',
|
||||
'price': 0,
|
||||
'skill_level': 0,
|
||||
'join_message': '',
|
||||
'contact_info': '',
|
||||
'cancel_reason': '',
|
||||
'joined_at': 'CURRENT_TIMESTAMP'
|
||||
}, async (newRow) => {
|
||||
let res = await gameParticipantsServer.add(newRow)
|
||||
rootVue.$Message.success('新增成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
async showViewWarp(row) {
|
||||
this.$refs.editModal.viewShow(row)
|
||||
},
|
||||
async showEditWarp(row) {
|
||||
this.$refs.editModal.editShow(row, async (newRow) => {
|
||||
let valid = await this.$refs['editModal'].$refs['From'].validate()
|
||||
if (valid) {
|
||||
let res = await gameParticipantsServer.edit(newRow)
|
||||
rootVue.$Message.success('修改成功!')
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
},
|
||||
async delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await gameParticipantsServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'game_id',
|
||||
value: '',
|
||||
status: null,
|
||||
payment_status: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
async exportCsv(row) {
|
||||
await gameParticipantsServer.exportCsv(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
||||
553
demo/src/views/ball/games.vue
Normal file
553
demo/src/views/ball/games.vue
Normal file
@@ -0,0 +1,553 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="球局类型">
|
||||
<Select v-model="gridOption.param.seachOption.game_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="个人球局">个人球局</Option>
|
||||
<Option value="团队球局">团队球局</Option>
|
||||
<Option value="比赛球局">比赛球局</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="玩法类型">
|
||||
<Select v-model="gridOption.param.seachOption.play_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="单打">单打</Option>
|
||||
<Option value="双打">双打</Option>
|
||||
<Option value="混合双打">混合双打</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<Select v-model="gridOption.param.seachOption.match_status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option :value="0">未开始</Option>
|
||||
<Option :value="1">进行中</Option>
|
||||
<Option :value="2">已结束</Option>
|
||||
<Option :value="3">已取消</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import menuServer from '@/api/system_high/menuServer.js'
|
||||
import gamesServer from '@/api/ball/games_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["id"] = [{ required: true, message: '请填写' }];
|
||||
rules["title"] = [{ required: true, message: '请填写球局标题' }];
|
||||
rules["description"] = [{ required: true, message: '请填写球局描述' }];
|
||||
rules["game_type"] = [{ required: true, message: '请填写球局类型' }];
|
||||
rules["publisher_id"] = [{ required: true, message: '请填写发布者ID' }];
|
||||
rules["venue_id"] = [{ required: true, message: '请填写场地ID' }];
|
||||
rules["max_players"] = [{ required: true, type: "number", message: '请填写最大参与人数', trigger: 'change' }];
|
||||
rules["current_players"] = [{ required: false, type: "number", message: '请填写当前参与人数', trigger: 'change' }];
|
||||
rules["start_time"] = [{ required: true, message: '请选择开始时间', trigger: 'change' }];
|
||||
rules["end_time"] = [{ required: true, message: '请选择结束时间', trigger: 'change' }];
|
||||
rules["price"] = [{ required: true, type: "number", message: '请填写价格', trigger: 'change' }];
|
||||
rules["price_mode"] = [{ required: true, message: '请选择费用模式', trigger: 'change' }];
|
||||
rules["court_type"] = [{ required: true, message: '请选择场地类型', trigger: 'change' }];
|
||||
rules["court_surface"] = [{ required: true, message: '请选择场地材质', trigger: 'change' }];
|
||||
rules["gender_limit"] = [{ required: true, message: '请选择性别限制', trigger: 'change' }];
|
||||
rules["skill_level_min"] = [{ required: false, type: "number", message: '请填写最低水平(NTRP)', trigger: 'change' }];
|
||||
rules["skill_level_max"] = [{ required: false, type: "number", message: '请填写最高水平(NTRP)', trigger: 'change' }];
|
||||
rules["is_urgent"] = [{ required: true, message: '请选择是否急招', trigger: 'change' }];
|
||||
rules["is_substitute_supported"] = [{ required: true, message: '请选择是否支持替补', trigger: 'change' }];
|
||||
rules["privacy_level"] = [{ required: true, message: '请选择隐私级别', trigger: 'change' }];
|
||||
rules["member_visibility"] = [{ required: true, message: '请选择成员可见性', trigger: 'change' }];
|
||||
rules["match_status"] = [{ required: true, message: '请选择状态', trigger: 'change' }];
|
||||
rules["location"] = [{ required: false, message: '请填写位置信息' }];
|
||||
rules["latitude"] = [{ required: false, type: "number", message: '请填写纬度', trigger: 'change' }];
|
||||
rules["longitude"] = [{ required: false, type: "number", message: '请填写经度', trigger: 'change' }];
|
||||
rules["play_type"] = [{ required: true, message: '请选择玩法类型', trigger: 'change' }];
|
||||
rules["is_wechat_contact"] = [{ required: false, type: "number", message: '请选择是否允许微信联系', trigger: 'change' }];
|
||||
rules["wechat_contact"] = [{ required: false, message: '请填写微信号' }];
|
||||
rules["venue_description"] = [{ required: false, message: '请填写场地描述' }];
|
||||
rules["venue_image_list"] = [{ required: false, message: '请上传场地预定截图' }];
|
||||
rules["location_name"] = [{ required: false, message: '请填写位置名称' }];
|
||||
rules["remark"] = [{ required: false, message: '请填写备注' }];
|
||||
|
||||
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: "title", value: "球局标题" },
|
||||
{ key: "description", value: "球局描述" },
|
||||
{ key: "publisher_id", value: "发布者ID" },
|
||||
{ key: "venue_id", value: "场地ID" },
|
||||
{ key: "location_name", value: "位置名称" }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: "title",
|
||||
value: "",
|
||||
game_type: null, // 球局类型筛选
|
||||
play_type: null, // 玩法类型筛选
|
||||
match_status: null // 状态筛选
|
||||
},
|
||||
pageOption: {
|
||||
total: 0,
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
rules,
|
||||
columns: [
|
||||
{ key: 'id', title: 'id', minWidth: 80, is_show_edit: 0 },
|
||||
|
||||
{ key: "id", title: "ID", disabled: true, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{
|
||||
key: "title",
|
||||
title: "标题",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Input",
|
||||
|
||||
render: (h, params) => {
|
||||
const title = params.row.title || '';
|
||||
const displayText = title.length > 15 ? title.substring(0, 15) + '...' : title;
|
||||
return h('span', { attrs: { title: title } }, displayText);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
key: "game_type",
|
||||
title: "类型",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
|
||||
options: [
|
||||
{ value: "个人球局", label: "个人球局" },
|
||||
{ value: "团队球局", label: "团队球局" },
|
||||
{ value: "比赛球局", label: "比赛球局" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const typeMap = {
|
||||
'个人球局': { text: '个人', color: 'blue' },
|
||||
'团队球局': { text: '团队', color: 'green' },
|
||||
'比赛球局': { text: '比赛', color: 'purple' }
|
||||
};
|
||||
const type = typeMap[params.row.game_type] || { text: params.row.game_type || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: type.color } }, type.text);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "play_type",
|
||||
title: "玩法",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
|
||||
options: [
|
||||
{ value: "单打", label: "单打" },
|
||||
{ value: "双打", label: "双打" },
|
||||
{ value: "混合双打", label: "混合双打" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const playMap = {
|
||||
'单打': { text: '单打', color: 'orange' },
|
||||
'双打': { text: '双打', color: 'cyan' },
|
||||
'混合双打': { text: '混双', color: 'pink' }
|
||||
};
|
||||
const play = playMap[params.row.play_type] || { text: params.row.play_type || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: play.color } }, play.text);
|
||||
}
|
||||
},
|
||||
{ key: "publisher_id", title: "发布者ID", disabled: true, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "venue_id", title: "场地ID", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{
|
||||
key: "max_players",
|
||||
title: "最大人数",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
data_type: "number",
|
||||
com: "InputNumber",
|
||||
render: (h, params) => {
|
||||
const max = params.row.max_players || 0;
|
||||
return h('span', { style: { color: '#2d8cf0' } }, `${max}人`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "current_players",
|
||||
title: "当前人数",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
data_type: "number",
|
||||
com: "InputNumber",
|
||||
render: (h, params) => {
|
||||
const current = params.row.current_players || 0;
|
||||
const max = params.row.max_players || 0;
|
||||
const color = current >= max ? '#f56c6c' : '#67c23a';
|
||||
return h('span', { style: { color: color } }, `${current}人`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "start_time",
|
||||
title: "开始时间",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "DatePicker",
|
||||
|
||||
render: (h, params) => {
|
||||
const time = params.row.start_time;
|
||||
if (!time) {
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '未设置');
|
||||
}
|
||||
// 只显示月-日 时:分
|
||||
const date = new Date(time);
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
const displayTime = `${month}-${day} ${hour}:${minute}`;
|
||||
return h('span', { attrs: { title: time } }, displayTime);
|
||||
}
|
||||
},
|
||||
{ key: "end_time", title: "结束时间", disabled: false, is_show_edit: 1, is_show_list: 0, com: "DatePicker" },
|
||||
{
|
||||
key: "price",
|
||||
title: "价格",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "InputNumber",
|
||||
data_type: "number",
|
||||
|
||||
render: (h, params) => {
|
||||
const price = params.row.price;
|
||||
if (price === null || price === undefined || price === 0) {
|
||||
return h('Tag', { props: { color: 'green' } }, '免费');
|
||||
}
|
||||
return h('span', { style: { color: '#f56c6c', fontWeight: 'bold' } }, `¥${price}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "price_mode", title: "费用模式", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Select", options: [
|
||||
{ value: "AA", label: "AA制" },
|
||||
{ value: "免费", label: "免费" },
|
||||
{ value: "付费", label: "付费" }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "court_type",
|
||||
title: "场地类型",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "室内", label: "室内" },
|
||||
{ value: "室外", label: "室外" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const typeMap = {
|
||||
'室内': { text: '室内', color: 'blue' },
|
||||
'室外': { text: '室外', color: 'green' }
|
||||
};
|
||||
const type = typeMap[params.row.court_type] || { text: params.row.court_type || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: type.color } }, type.text);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "court_surface",
|
||||
title: "场地材质",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "硬地", label: "硬地" },
|
||||
{ value: "红土", label: "红土" },
|
||||
{ value: "草地", label: "草地" },
|
||||
{ value: "地毯", label: "地毯" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const surfaceMap = {
|
||||
'硬地': { text: '硬地', color: 'cyan' },
|
||||
'红土': { text: '红土', color: 'orange' },
|
||||
'草地': { text: '草地', color: 'green' },
|
||||
'地毯': { text: '地毯', color: 'purple' }
|
||||
};
|
||||
const surface = surfaceMap[params.row.court_surface] || { text: params.row.court_surface || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: surface.color } }, surface.text);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "gender_limit",
|
||||
title: "性别限制",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "0", label: "不限" },
|
||||
{ value: "1", label: "仅限男生" },
|
||||
{ value: "2", label: "仅限女生" },
|
||||
{ value: "3", label: "仅限同性" },
|
||||
{ value: "4", label: "仅限异性" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const genderMap = {
|
||||
'0': { text: '不限', color: 'default' },
|
||||
'1': { text: '仅限男生', color: 'blue' },
|
||||
'2': { text: '仅限女生', color: 'pink' },
|
||||
'3': { text: '仅限同性', color: 'purple' },
|
||||
'4': { text: '仅限异性', color: 'orange' }
|
||||
};
|
||||
const gender = genderMap[params.row.gender_limit] || { text: '不限', color: 'default' };
|
||||
return h('Tag', { props: { color: gender.color } }, gender.text);
|
||||
}
|
||||
},
|
||||
{ key: "skill_level_min", title: "最低水平(NTRP)", disabled: false, is_show_edit: 1, is_show_list: 0, com: "InputNumber", data_type: "number" },
|
||||
{ key: "skill_level_max", title: "最高水平(NTRP)", disabled: false, is_show_edit: 1, is_show_list: 0, com: "InputNumber", data_type: "number" },
|
||||
{
|
||||
key: "is_urgent", title: "是否急招", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Radio", options: [
|
||||
{ value: "0", label: "否" },
|
||||
{ value: "1", label: "是" }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "is_substitute_supported", title: "支持替补", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Radio", options: [
|
||||
{ value: "0", label: "否" },
|
||||
{ value: "1", label: "是" }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "is_wechat_contact", title: "微信联系", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Radio", options: [
|
||||
{ value: 0, label: "否" },
|
||||
{ value: 1, label: "是" }
|
||||
]
|
||||
},
|
||||
{ key: "wechat_contact", title: "微信号", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "substitute_limit", title: "替补人数", disabled: false, is_show_edit: 1, is_show_list: 0, data_type: "number", com: "InputNumber" },
|
||||
{
|
||||
key: "privacy_level", title: "隐私级别", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Select", options: [
|
||||
{ value: "public", label: "公开" },
|
||||
{ value: "private", label: "私密" },
|
||||
{ value: "friends", label: "仅好友" }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "member_visibility", title: "成员可见性", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Select", options: [
|
||||
{ value: "all", label: "所有人" },
|
||||
{ value: "participants", label: "仅参与者" },
|
||||
{ value: "friends", label: "仅好友" }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "match_status",
|
||||
title: "状态",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: 0, label: "未开始" },
|
||||
{ value: 1, label: "进行中" },
|
||||
{ value: 2, label: "已结束" },
|
||||
{ value: 3, label: "已取消" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const statusMap = {
|
||||
0: { text: '未开始', color: 'blue' },
|
||||
1: { text: '进行中', color: 'green' },
|
||||
2: { text: '已结束', color: 'gray' },
|
||||
3: { text: '已取消', color: 'red' }
|
||||
};
|
||||
const status = statusMap[params.row.match_status] || { text: '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: status.color } }, status.text);
|
||||
}
|
||||
},
|
||||
{ key: "venue_description", title: "场地描述", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "venue_image_list", title: "预定截图", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Upload", action: "/api/upload" },
|
||||
{ key: "location_name", title: "位置名称", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "location", title: "位置信息", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "latitude", title: "纬度", disabled: false, is_show_edit: 1, is_show_list: 0, com: "InputNumber", data_type: "number" },
|
||||
{ key: "longitude", title: "经度", disabled: false, is_show_edit: 1, is_show_list: 0, com: "InputNumber", data_type: "number" },
|
||||
{ key: "deadline_hours", title: "截止时间(小时)", disabled: false, is_show_edit: 1, is_show_list: 0, data_type: "number", com: "InputNumber" },
|
||||
{ key: "remark", title: "备注", disabled: false, is_show_edit: 1, is_show_list: 0, com: "TextArea" },
|
||||
{ key: "description", title: "球局描述", disabled: false, is_show_edit: 1, is_show_list: 0, com: "TextArea" },
|
||||
{ key: "last_modify_time", title: "更新时间", disabled: true, is_show_edit: 1, is_show_list: 0, com: "DatePicker" },
|
||||
{ key: 'create_time', title: '创建时间', minWidth: 100, is_show_edit: 0 },
|
||||
{ key: 'last_modify_time', title: '更新时间', minWidth: 100, is_show_edit: 0 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
is_show_list: 1,
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '修改',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
},],
|
||||
data: []
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
},
|
||||
editColumns() {
|
||||
let editTempColumns = this.gridOption.columns.filter(p => p.is_show_edit === 1)
|
||||
return editTempColumns
|
||||
},
|
||||
listColumns() {
|
||||
let listTempColumns = this.gridOption.columns.filter(p => p.is_show_list === 1)
|
||||
return listTempColumns
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.initCol()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.query(1)
|
||||
},
|
||||
async initCol() {
|
||||
|
||||
let columnRows = []
|
||||
let columnKeys = columnRows.map(p => p.key)
|
||||
let newColumns = this.gridOption.columns.filter(p => columnKeys.indexOf(p.key) > -1)
|
||||
for (let i = 0; i < newColumns.length; i++) {
|
||||
let curColumn = newColumns[i]
|
||||
let modelMap = columnRows[i].map_option
|
||||
let res = await menuServer.modelInterface({ model_key: columnRows[i].modelKey, map_option: modelMap })
|
||||
curColumn.source = res.data
|
||||
}
|
||||
|
||||
},
|
||||
async inquiry() {
|
||||
let res = await gamesServer.all(this.gridOption.param)
|
||||
this.gridOption.data = res.data
|
||||
},
|
||||
async query(page) {
|
||||
if (page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
}
|
||||
let res = await gamesServer.page(this.gridOption.param)
|
||||
this.gridOption.data = res.data.rows
|
||||
this.gridOption.param.pageOption.total = res.data.count
|
||||
},
|
||||
async showAddWarp() {
|
||||
this.$refs.editModal.addShow({
|
||||
'title': '',
|
||||
'description': '',
|
||||
'game_type': '个人球局',
|
||||
'play_type': '双打',
|
||||
'publisher_id': '',
|
||||
'venue_id': '',
|
||||
'max_players': 4,
|
||||
'current_players': 0,
|
||||
'start_time': '',
|
||||
'end_time': '',
|
||||
'price': 0,
|
||||
'price_mode': 'AA',
|
||||
'court_type': '室外',
|
||||
'court_surface': '硬地',
|
||||
'gender_limit': 0,
|
||||
'skill_level_min': 1.0,
|
||||
'skill_level_max': 7.0,
|
||||
'is_urgent': 0,
|
||||
'is_substitute_supported': 0,
|
||||
'is_wechat_contact': 0,
|
||||
'wechat_contact': '',
|
||||
'substitute_limit': 0,
|
||||
'privacy_level': 'public',
|
||||
'member_visibility': 'all',
|
||||
'match_status': 0,
|
||||
'location': '',
|
||||
'location_name': '',
|
||||
'latitude': 0,
|
||||
'longitude': 0,
|
||||
'deadline_hours': 1,
|
||||
'venue_description': '',
|
||||
'remark': ''
|
||||
}, async (newRow) => {
|
||||
let res = await gamesServer.add(newRow)
|
||||
rootVue.$Message.success('新增成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
async showEditWarp(row) {
|
||||
this.$refs.editModal.editShow(row, async (newRow) => {
|
||||
let valid = await this.$refs['editModal'].$refs['From'].validate()
|
||||
if (valid) {
|
||||
let res = await gamesServer.edit(newRow)
|
||||
rootVue.$Message.success('修改成功!')
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
},
|
||||
async delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await gamesServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'title',
|
||||
value: '',
|
||||
game_type: null,
|
||||
play_type: null,
|
||||
match_status: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
async exportCsv(row) {
|
||||
await gamesServer.exportCsv(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
297
demo/src/views/ball/venues.vue
Normal file
297
demo/src/views/ball/venues.vue
Normal file
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="场地类型">
|
||||
<Select v-model="gridOption.param.seachOption.venue_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="indoor">室内</Option>
|
||||
<Option value="outdoor">室外</Option>
|
||||
<Option value="semi-outdoor">半室外</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="地面类型">
|
||||
<Select v-model="gridOption.param.seachOption.surface_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="hard">硬地</Option>
|
||||
<Option value="clay">红土</Option>
|
||||
<Option value="grass">草地</Option>
|
||||
<Option value="carpet">地毯</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="active">营业中</Option>
|
||||
<Option value="inactive">暂停营业</Option>
|
||||
<Option value="closed">已关闭</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import menuServer from '@/api/system_high/menuServer.js'
|
||||
import venuesServer from '@/api/ball/venues_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["id"] = [{ required: true, message: '请填写' }];
|
||||
rules["name"] = [{ required: true, message: '请填写场地名称' }];
|
||||
rules["address"] = [{ required: true, message: '请填写详细地址' }];
|
||||
rules["latitude"] = [{ required: true, message: '请填写纬度' }];
|
||||
rules["longitude"] = [{ required: true, message: '请填写经度' }];
|
||||
rules["venue_type"] = [{ required: true, message: '请填写场地类型' }];
|
||||
rules["court_count"] = [{ required: true, type: "number", message: '请选择场地数量', trigger: 'change' }];
|
||||
rules["price_per_hour"] = [{ required: true, message: '请填写每小时价格' }];
|
||||
rules["facilities"] = [{ required: true, message: '请填写设施描述' }];
|
||||
rules["surface_type"] = [{ required: true, message: '请选择地面类型' }];
|
||||
rules["timeSlot"] = [{ required: false, message: '请填写营业时间' }];
|
||||
|
||||
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: "name", value: "场地名称" },
|
||||
{ key: "address", value: "详细地址" },
|
||||
{ key: "facilities", value: "设施描述" }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: "name",
|
||||
value: "",
|
||||
venue_type: null, // 场地类型筛选
|
||||
surface_type: null, // 地面类型筛选
|
||||
status: null // 状态筛选
|
||||
},
|
||||
pageOption: {
|
||||
total: 0,
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
rules,
|
||||
columns: [
|
||||
{ key: 'id', title: 'id', is_show_edit: 0 },
|
||||
{ key: "name", title: "场地名称", disabled: false, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{ key: "address", title: "详细地址", disabled: false, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{ key: "latitude", title: "纬度", disabled: false, is_show_edit: 1, is_show_list: 1, com: "InputNumber", data_type: "number" },
|
||||
{ key: "longitude", title: "经度", disabled: false, is_show_edit: 1, is_show_list: 1, com: "InputNumber", data_type: "number" },
|
||||
{
|
||||
key: "venue_type",
|
||||
title: "场地类型",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "indoor", label: "室内" },
|
||||
{ value: "outdoor", label: "室外" },
|
||||
{ value: "semi-outdoor", label: "半室外" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const typeMap = {
|
||||
'indoor': { text: '室内', color: 'blue' },
|
||||
'outdoor': { text: '室外', color: 'green' },
|
||||
'semi-outdoor': { text: '半室外', color: 'cyan' }
|
||||
};
|
||||
const type = typeMap[params.row.venue_type] || { text: params.row.venue_type || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: type.color } }, type.text);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "surface_type",
|
||||
title: "地面类型",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "hard", label: "硬地" },
|
||||
{ value: "clay", label: "红土" },
|
||||
{ value: "grass", label: "草地" },
|
||||
{ value: "carpet", label: "地毯" },
|
||||
{ value: "indoor", label: "室内地面" },
|
||||
{ value: "other", label: "其他" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const surfaceMap = {
|
||||
'hard': { text: '硬地', color: 'cyan' },
|
||||
'clay': { text: '红土', color: 'orange' },
|
||||
'grass': { text: '草地', color: 'green' },
|
||||
'carpet': { text: '地毯', color: 'purple' },
|
||||
'indoor': { text: '室内地面', color: 'blue' },
|
||||
'other': { text: '其他', color: 'default' }
|
||||
};
|
||||
const surface = surfaceMap[params.row.surface_type] || { text: params.row.surface_type || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: surface.color } }, surface.text);
|
||||
}
|
||||
},
|
||||
{ key: "court_count", title: "场地数量", disabled: false, is_show_edit: 1, is_show_list: 1, data_type: "number", com: "InputNumber" },
|
||||
{ key: "price_per_hour", title: "每小时价格", disabled: false, is_show_edit: 1, is_show_list: 1, com: "InputNumber", data_type: "number" },
|
||||
{ key: "facilities", title: "设施描述", disabled: false, is_show_edit: 1, is_show_list: 0, com: "TextArea" },
|
||||
{ key: "timeSlot", title: "营业时间", disabled: false, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{
|
||||
key: "status",
|
||||
title: "状态",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
options: [
|
||||
{ value: "active", label: "营业中" },
|
||||
{ value: "inactive", label: "暂停营业" },
|
||||
{ value: "closed", label: "已关闭" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const statusMap = {
|
||||
'active': { text: '营业中', color: 'green' },
|
||||
'inactive': { text: '暂停营业', color: 'orange' },
|
||||
'closed': { text: '已关闭', color: 'red' }
|
||||
};
|
||||
const status = statusMap[params.row.status] || { text: params.row.status || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: status.color } }, status.text);
|
||||
}
|
||||
},
|
||||
{ key: 'create_time', title: '创建时间', is_show_edit: 0 },
|
||||
{ key: 'last_modify_time', title: '更新时间', is_show_edit: 0 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '修改',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
|
||||
],
|
||||
data: []
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
},
|
||||
editColumns() {
|
||||
let editTempColumns = this.gridOption.columns.filter(p => p.is_show_edit === 1)
|
||||
return editTempColumns
|
||||
},
|
||||
listColumns() {
|
||||
let listTempColumns = this.gridOption.columns.filter(p => p.is_show_list !== 0)
|
||||
return listTempColumns
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.initCol()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.query(1)
|
||||
},
|
||||
async initCol() {
|
||||
|
||||
let columnRows = []
|
||||
let columnKeys = columnRows.map(p => p.key)
|
||||
let newColumns = this.gridOption.columns.filter(p => columnKeys.indexOf(p.key) > -1)
|
||||
for (let i = 0; i < newColumns.length; i++) {
|
||||
let curColumn = newColumns[i]
|
||||
let modelMap = columnRows[i].map_option
|
||||
let res = await menuServer.modelInterface({ model_key: columnRows[i].modelKey, map_option: modelMap })
|
||||
curColumn.source = res.data
|
||||
}
|
||||
|
||||
},
|
||||
async inquiry() {
|
||||
let res = await venuesServer.all(this.gridOption.param)
|
||||
this.gridOption.data = res.data
|
||||
},
|
||||
async query(page) {
|
||||
if (page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
}
|
||||
let res = await venuesServer.page(this.gridOption.param)
|
||||
this.gridOption.data = res.data.rows
|
||||
this.gridOption.param.pageOption.total = res.data.count
|
||||
},
|
||||
async showAddWarp() {
|
||||
this.$refs.editModal.addShow({ 'venue_type': 'indoor', 'surface_type': 'hard', 'court_count': '1', 'status': 'active', 'create_time': 'CURRENT_TIMESTAMP', 'updated_at': 'CURRENT_TIMESTAMP', }, async (newRow) => {
|
||||
let res = await venuesServer.add(newRow)
|
||||
rootVue.$Message.success('新增成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
async showEditWarp(row) {
|
||||
this.$refs.editModal.editShow(row, async (newRow) => {
|
||||
let valid = await this.$refs['editModal'].$refs['From'].validate()
|
||||
if (valid) {
|
||||
let res = await venuesServer.edit(newRow)
|
||||
rootVue.$Message.success('修改成功!')
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
},
|
||||
async delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await venuesServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'name',
|
||||
value: '',
|
||||
venue_type: null,
|
||||
surface_type: null,
|
||||
status: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
async exportCsv(row) {
|
||||
await venuesServer.exportCsv(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
357
demo/src/views/ball/wch_users.vue
Normal file
357
demo/src/views/ball/wch_users.vue
Normal file
@@ -0,0 +1,357 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="性别">
|
||||
<Select v-model="gridOption.param.seachOption.gender" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option :value="0">未知</Option>
|
||||
<Option :value="1">男</Option>
|
||||
<Option :value="2">女</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="NTRP等级">
|
||||
<Select v-model="gridOption.param.seachOption.ntrp_level" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option :value="1">1.0</Option>
|
||||
<Option :value="2">2.0</Option>
|
||||
<Option :value="3">3.0</Option>
|
||||
<Option :value="4">4.0</Option>
|
||||
<Option :value="5">5.0</Option>
|
||||
<Option :value="6">6.0</Option>
|
||||
<Option :value="7">7.0</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import menuServer from '@/api/system_high/menuServer.js'
|
||||
import wch_usersServer from '@/api/ball/wch_users_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["nickname"] = [{ required: true, message: '请填写微信昵称' }];
|
||||
rules["phone"] = [{ required: false, message: '请填写手机号' }];
|
||||
rules["ntrp_level"] = [{ required: false, type: "number", message: '请填写网球等级', trigger: 'change' }];
|
||||
rules["occupation"] = [{ required: false, message: '请填写职业' }];
|
||||
rules["openid"] = [{ required: false, message: '请填写微信openid' }];
|
||||
rules["unionid"] = [{ required: false, message: '请填写微信unionid' }];
|
||||
rules["session_key"] = [{ required: false, message: '请填写会话密钥' }];
|
||||
rules["avatar_url"] = [{ required: false, message: '请填写微信头像URL' }];
|
||||
rules["gender"] = [{ required: false, type: "number", message: '请选择性别', trigger: 'change' }];
|
||||
rules["country"] = [{ required: false, message: '请填写国家' }];
|
||||
rules["province"] = [{ required: false, message: '请填写省份' }];
|
||||
rules["city"] = [{ required: false, message: '请填写城市' }];
|
||||
rules["language"] = [{ required: false, message: '请填写语言' }];
|
||||
rules["is_subscribed"] = [{ required: false, type: "number", message: '请选择是否关注公众号', trigger: 'change' }];
|
||||
rules["subscribe_time"] = [{ required: false, message: '请填写关注时间', trigger: 'change' }];
|
||||
rules["last_login_time"] = [{ required: false, message: '请填写最后登录时间', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: "id", value: "用户ID" },
|
||||
{ key: "nickname", value: "昵称" },
|
||||
{ key: "phone", value: "手机号" }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: "nickname",
|
||||
value: "",
|
||||
gender: null, // 性别筛选
|
||||
ntrp_level: null // NTRP等级筛选
|
||||
},
|
||||
pageOption: {
|
||||
total: 0,
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
rules,
|
||||
columns: [
|
||||
{ key: "id", title: "ID", disabled: true, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{ key: "openid", title: "微信openid", disabled: true, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "unionid", title: "微信unionid", disabled: true, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "session_key", title: "会话密钥", disabled: true, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{
|
||||
key: "nickname",
|
||||
title: "昵称",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Input",
|
||||
|
||||
render: (h, params) => {
|
||||
const nickname = params.row.nickname || '';
|
||||
const displayText = nickname.length > 10 ? nickname.substring(0, 10) + '...' : nickname;
|
||||
return h('span', { attrs: { title: nickname } }, displayText);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "avatar_url",
|
||||
title: "头像",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "UploadSingle",
|
||||
|
||||
render: (h, params) => {
|
||||
if (!params.row.avatar_url) {
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '无头像');
|
||||
}
|
||||
return h('div', {
|
||||
style: {
|
||||
'display': 'flex',
|
||||
'justify-content': 'center',
|
||||
'align-items': 'center',
|
||||
'padding': '4px 0'
|
||||
}
|
||||
}, [
|
||||
h('img', {
|
||||
style: {
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
borderRadius: '50%',
|
||||
objectFit: 'cover',
|
||||
cursor: 'pointer'
|
||||
},
|
||||
attrs: {
|
||||
src: params.row.avatar_url,
|
||||
alt: params.row.nickname || '头像',
|
||||
title: '点击查看大图'
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
// 点击查看大图
|
||||
this.$Modal.info({
|
||||
title: params.row.nickname + ' 的头像',
|
||||
render: (h) => {
|
||||
return h('div', { style: { textAlign: 'center' } }, [
|
||||
h('img', {
|
||||
style: {
|
||||
maxWidth: '100%',
|
||||
maxHeight: '400px',
|
||||
borderRadius: '8px'
|
||||
},
|
||||
attrs: { src: params.row.avatar_url }
|
||||
})
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
]);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "gender",
|
||||
title: "性别",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Radio",
|
||||
|
||||
options: [
|
||||
{ value: 0, label: "未知" },
|
||||
{ value: 1, label: "男" },
|
||||
{ value: 2, label: "女" }
|
||||
],
|
||||
render: (h, params) => {
|
||||
const genderMap = {
|
||||
0: { text: '未知', color: 'default' },
|
||||
1: { text: '男', color: 'blue' },
|
||||
2: { text: '女', color: 'pink' }
|
||||
};
|
||||
const gender = genderMap[params.row.gender] || { text: '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: gender.color } }, gender.text);
|
||||
}
|
||||
},
|
||||
{ key: "country", title: "国家", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "province", title: "省份", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{ key: "city", title: "城市", disabled: false, is_show_edit: 1, is_show_list: 1, com: "Input" },
|
||||
{ key: "language", title: "语言", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Input" },
|
||||
{
|
||||
key: "phone",
|
||||
title: "手机号",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "Input",
|
||||
|
||||
render: (h, params) => {
|
||||
const phone = params.row.phone || '';
|
||||
if (!phone) {
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '未填写');
|
||||
}
|
||||
// 手机号脱敏显示
|
||||
const maskedPhone = phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
|
||||
return h('span', { attrs: { title: phone } }, maskedPhone);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "ntrp_level",
|
||||
title: "等级",
|
||||
disabled: false,
|
||||
is_show_edit: 1,
|
||||
is_show_list: 1,
|
||||
com: "InputNumber",
|
||||
|
||||
render: (h, params) => {
|
||||
const level = params.row.ntrp_level;
|
||||
if (level === null || level === undefined || level === 0) {
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '未设置');
|
||||
}
|
||||
return h('Tag', { props: { color: 'blue' } }, `${level}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "is_subscribed", title: "是否关注公众号", disabled: false, is_show_edit: 1, is_show_list: 0, com: "Radio", options: [
|
||||
{ value: 0, label: "否" },
|
||||
{ value: 1, label: "是" }
|
||||
]
|
||||
},
|
||||
{ key: "subscribe_time", title: "关注时间", disabled: true, is_show_edit: 1, is_show_list: 0, com: "DatePicker" },
|
||||
{ key: "last_login_time", title: "最后登录时间", disabled: true, is_show_edit: 1, is_show_list: 0, com: "DatePicker" },
|
||||
{ key: 'create_time', title: '创建时间', minWidth: 100, is_show_edit: 0, com: "DatePicker" },
|
||||
{ key: 'last_modify_time', title: '更新时间', minWidth: 100, is_show_edit: 0, com: "DatePicker" },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
is_show_list: 1,
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '修改',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
},],
|
||||
data: []
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
},
|
||||
editColumns() {
|
||||
let editTempColumns = this.gridOption.columns.filter(p => p.is_show_edit === 1)
|
||||
return editTempColumns
|
||||
},
|
||||
listColumns() {
|
||||
let listTempColumns = this.gridOption.columns.filter(p => p.is_show_list === 1)
|
||||
return listTempColumns
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.initCol()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.query(1)
|
||||
},
|
||||
async initCol() {
|
||||
|
||||
let columnRows = []
|
||||
let columnKeys = columnRows.map(p => p.key)
|
||||
let newColumns = this.gridOption.columns.filter(p => columnKeys.indexOf(p.key) > -1)
|
||||
for (let i = 0; i < newColumns.length; i++) {
|
||||
let curColumn = newColumns[i]
|
||||
let modelMap = columnRows[i].map_option
|
||||
let res = await menuServer.modelInterface({ model_key: columnRows[i].modelKey, map_option: modelMap })
|
||||
curColumn.source = res.data
|
||||
}
|
||||
|
||||
},
|
||||
async inquiry() {
|
||||
let res = await wch_usersServer.all(this.gridOption.param)
|
||||
this.gridOption.data = res.data
|
||||
},
|
||||
async query(page) {
|
||||
if (page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
}
|
||||
let res = await wch_usersServer.page(this.gridOption.param)
|
||||
this.gridOption.data = res.data.rows
|
||||
this.gridOption.param.pageOption.total = res.data.count
|
||||
},
|
||||
async showAddWarp() {
|
||||
this.$refs.editModal.addShow({ 'is_subscribed': '0', 'last_login_time': 'CURRENT_TIMESTAMP', 'create_time': 'CURRENT_TIMESTAMP', 'updated_at': 'CURRENT_TIMESTAMP', }, async (newRow) => {
|
||||
let res = await wch_usersServer.add(newRow)
|
||||
rootVue.$Message.success('新增成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
async showEditWarp(row) {
|
||||
this.$refs.editModal.editShow(row, async (newRow) => {
|
||||
let valid = await this.$refs['editModal'].$refs['From'].validate()
|
||||
if (valid) {
|
||||
let res = await wch_usersServer.edit(newRow)
|
||||
rootVue.$Message.success('修改成功!')
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
},
|
||||
async delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await wch_usersServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
gender: null,
|
||||
ntrp_level: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
async exportCsv(row) {
|
||||
await wch_usersServer.exportCsv(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
394
demo/src/views/business/hot_city_qr.vue
Normal file
394
demo/src/views/business/hot_city_qr.vue
Normal file
@@ -0,0 +1,394 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增城市二维码</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem label="城市名称" :label-width="80">
|
||||
<Input v-model="gridOption.param.seachOption.city_name" style="width: 200px" placeholder="请输入城市名称"
|
||||
@on-enter="query(1)" clearable />
|
||||
</FormItem>
|
||||
<FormItem label="状态" :label-width="60">
|
||||
<Select v-model="gridOption.param.seachOption.is_active" style="width: 120px" clearable>
|
||||
<Option :value="1">启用</Option>
|
||||
<Option :value="0">禁用</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="warning" @click="batchDelete" class="ml10" :disabled="selectedIds.length === 0">
|
||||
批量删除 ({{ selectedIds.length }})
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query" @on-selection-change="handleSelectionChange"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import hotCityQrServer from '@/api/business/hot_city_qr_server.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["city_name"] = [{ required: true, message: '请填写城市名称', trigger: 'blur' }];
|
||||
rules["qr_code_url"] = [{ required: true, message: '请上传二维码图片', trigger: 'change' }];
|
||||
rules["sort_order"] = [{ required: false, type: "number", message: '请填写排序顺序', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
selectedIds: [],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
city_name: '',
|
||||
is_active: ''
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{
|
||||
type: 'selection',
|
||||
width: 60,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 80,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '城市名称',
|
||||
key: 'city_name',
|
||||
minWidth: 120,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '二维码图片',
|
||||
key: 'qr_code_url',
|
||||
minWidth: 150,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
if (params.row.qr_code_url) {
|
||||
return h('div', {
|
||||
style: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '10px'
|
||||
}
|
||||
}, [
|
||||
h('img', {
|
||||
attrs: {
|
||||
src: params.row.qr_code_url,
|
||||
alt: '二维码'
|
||||
},
|
||||
style: {
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
objectFit: 'contain',
|
||||
cursor: 'pointer',
|
||||
border: '1px solid #ddd',
|
||||
borderRadius: '4px'
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
this.previewImage(params.row.qr_code_url)
|
||||
}
|
||||
}
|
||||
}),
|
||||
h('a', {
|
||||
attrs: {
|
||||
href: params.row.qr_code_url,
|
||||
target: '_blank'
|
||||
},
|
||||
style: {
|
||||
fontSize: '12px',
|
||||
color: '#2d8cf0'
|
||||
}
|
||||
}, '查看原图')
|
||||
])
|
||||
}
|
||||
return h('span', '-')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '描述说明',
|
||||
key: 'description',
|
||||
minWidth: 200,
|
||||
tooltip: true
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort_order',
|
||||
width: 100,
|
||||
sortable: true,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
return h('Tag', {
|
||||
props: {
|
||||
color: 'blue'
|
||||
}
|
||||
}, params.row.sort_order || 0)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'is_active',
|
||||
width: 100,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
return h('Tag', {
|
||||
props: {
|
||||
color: params.row.is_active === 1 ? 'success' : 'default'
|
||||
}
|
||||
}, params.row.is_active === 1 ? '启用' : '禁用')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'create_time',
|
||||
width: 160,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'update_time',
|
||||
width: 160,
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
size: 'small',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{
|
||||
title: '城市名称',
|
||||
key: 'city_name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
placeholder: '请输入城市名称,如:北京、上海'
|
||||
},
|
||||
{
|
||||
title: '二维码图片',
|
||||
key: 'qr_code_url',
|
||||
com: 'UploadSingle',
|
||||
required: true,
|
||||
uploadType: 'image',
|
||||
tip: '建议上传正方形图片,支持 JPG、PNG 格式'
|
||||
},
|
||||
{
|
||||
title: '描述说明',
|
||||
key: 'description',
|
||||
com: 'TextArea',
|
||||
placeholder: '请输入描述说明(选填)',
|
||||
rows: 3
|
||||
},
|
||||
{
|
||||
title: '排序顺序',
|
||||
key: 'sort_order',
|
||||
data_type: 'number',
|
||||
placeholder: '数字越小越靠前,默认为 0',
|
||||
min: 0,
|
||||
max: 9999
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
key: 'is_active',
|
||||
com: 'i-switch',
|
||||
data_type: 'boolean',
|
||||
activeValue: 1,
|
||||
inactiveValue: 0,
|
||||
activeText: '启用',
|
||||
inactiveText: '禁用'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1)
|
||||
},
|
||||
methods: {
|
||||
// 查询列表
|
||||
query(page) {
|
||||
if (page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
}
|
||||
|
||||
const params = {
|
||||
page: this.gridOption.param.pageOption.page,
|
||||
pageSize: this.gridOption.param.pageOption.pageSize,
|
||||
...this.gridOption.param.seachOption
|
||||
}
|
||||
|
||||
hotCityQrServer.page(params).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.gridOption.data = res.data.list || []
|
||||
this.gridOption.param.pageOption.total = res.data.total || 0
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 重置查询
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
city_name: '',
|
||||
is_active: ''
|
||||
}
|
||||
this.query(1)
|
||||
},
|
||||
|
||||
// 显示新增弹窗
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.addShow({
|
||||
city_name: '',
|
||||
qr_code_url: '',
|
||||
description: '',
|
||||
sort_order: 0,
|
||||
is_active: 1
|
||||
}, (data) => {
|
||||
hotCityQrServer.add(data).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('添加成功')
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '添加失败')
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 显示编辑弹窗
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.editShow(row, (data) => {
|
||||
hotCityQrServer.edit(row.id, data).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('编辑成功')
|
||||
this.query()
|
||||
} else {
|
||||
this.$Message.error(res.message || '编辑失败')
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 删除确认
|
||||
delConfirm(row) {
|
||||
this.$Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定要删除城市"${row.city_name}"的二维码配置吗?`,
|
||||
onOk: () => {
|
||||
hotCityQrServer.del(row.id).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('删除成功')
|
||||
this.query()
|
||||
} else {
|
||||
this.$Message.error(res.message || '删除失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 选择变化
|
||||
handleSelectionChange(selection) {
|
||||
this.selectedIds = selection.map(item => item.id)
|
||||
},
|
||||
|
||||
// 批量删除
|
||||
batchDelete() {
|
||||
if (this.selectedIds.length === 0) {
|
||||
this.$Message.warning('请先选择要删除的记录')
|
||||
return
|
||||
}
|
||||
|
||||
this.$Modal.confirm({
|
||||
title: '确认批量删除',
|
||||
content: `确定要删除选中的 ${this.selectedIds.length} 条记录吗?`,
|
||||
onOk: () => {
|
||||
hotCityQrServer.batchDel(this.selectedIds).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('批量删除成功')
|
||||
this.selectedIds = []
|
||||
this.query()
|
||||
} else {
|
||||
this.$Message.error(res.message || '批量删除失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 预览图片
|
||||
previewImage(url) {
|
||||
this.$Modal.info({
|
||||
title: '二维码预览',
|
||||
render: (h) => {
|
||||
return h('div', {
|
||||
style: {
|
||||
textAlign: 'center',
|
||||
padding: '20px'
|
||||
}
|
||||
}, [
|
||||
h('img', {
|
||||
attrs: {
|
||||
src: url,
|
||||
alt: '二维码'
|
||||
},
|
||||
style: {
|
||||
maxWidth: '100%',
|
||||
maxHeight: '500px'
|
||||
}
|
||||
})
|
||||
])
|
||||
},
|
||||
width: 600
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
187
demo/src/views/message/msg_notifications.vue
Normal file
187
demo/src/views/message/msg_notifications.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="消息类型">
|
||||
<Select v-model="gridOption.param.seachOption.type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="system">系统消息</Option>
|
||||
<Option value="game">球局消息</Option>
|
||||
<Option value="payment">支付消息</Option>
|
||||
<Option value="activity">活动消息</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="推送状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="pending">待发送</Option>
|
||||
<Option value="sent">已发送</Option>
|
||||
<Option value="failed">发送失败</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import msg_notificationsServer from '@/api/message/msg_notifications_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["user_id"] = [{ required: true, type: "number", message: '请填写用户ID', trigger: 'change' }];
|
||||
rules["title"] = [{ required: true, message: '请填写消息标题' }];
|
||||
rules["content"] = [{ required: true, message: '请填写消息内容' }];
|
||||
rules["type"] = [{ required: true, message: '请填写消息类型' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'title', value: '消息标题' }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'title',
|
||||
value: '',
|
||||
type: null,
|
||||
status: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '用户ID', key: 'user_id', minWidth: 120 },
|
||||
{ title: '用户昵称', key: 'nickname', minWidth: 120 },
|
||||
{ title: '消息标题', key: 'title', minWidth: 200 },
|
||||
{ title: '消息内容', key: 'content', minWidth: 300 },
|
||||
{ title: '消息类型', key: 'type', minWidth: 120 },
|
||||
{ title: '推送状态', key: 'status', minWidth: 120 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 150 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '发送',
|
||||
type: 'success',
|
||||
click: () => {
|
||||
this.sendMessage(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '用户ID', key: 'user_id', type: 'number', required: true },
|
||||
{ title: '消息标题', key: 'title', type: 'text', required: true },
|
||||
{ title: '消息内容', key: 'content', type: 'textarea', required: true },
|
||||
{ title: '消息类型', key: 'type', type: 'select', required: true, options: [
|
||||
{ value: 'game_reminder', label: '球局提醒' },
|
||||
{ value: 'payment_notification', label: '支付通知' },
|
||||
{ value: 'system_announcement', label: '系统公告' },
|
||||
{ value: 'activity_notification', label: '活动通知' }
|
||||
]},
|
||||
{ title: '推送时间', key: 'send_time', type: 'datetime' },
|
||||
{ title: '推送状态', key: 'status', type: 'select', options: [
|
||||
{ value: 'pending', label: '待发送' },
|
||||
{ value: 'sent', label: '已发送' },
|
||||
{ value: 'failed', label: '发送失败' }
|
||||
]}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
msg_notificationsServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
sendMessage(row) {
|
||||
this.$Message.info('发送功能暂未实现');
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await msg_notificationsServer.del(row)
|
||||
this.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
exportCsv() {
|
||||
msg_notificationsServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '消息通知.csv');
|
||||
});
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'title',
|
||||
value: '',
|
||||
type: null,
|
||||
status: null
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
243
demo/src/views/ntrp/ntr_questions.vue
Normal file
243
demo/src/views/ntrp/ntr_questions.vue
Normal file
@@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="启用状态">
|
||||
<Select v-model="gridOption.param.seachOption.is_active" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option :value="1">启用</Option>
|
||||
<Option :value="0">禁用</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules" @on-save="handleSave"></editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import ntr_questionsServer from '@/api/ntrp/ntr_questions_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["question_title"] = [{ required: true, message: '请填写题目标题' }];
|
||||
rules["question_content"] = [{ required: true, message: '请填写题目内容' }];
|
||||
rules["question_data"] = [{ required: true, message: '请填写题目数据' }];
|
||||
rules["sort_order"] = [{ required: true, type: "number", message: '请填写排序', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: 'question_title', value: '题目标题' },
|
||||
{ key: 'question_content', value: '题目内容' }
|
||||
],
|
||||
seachTypePlaceholder: '请选择搜索类型',
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'question_title',
|
||||
value: '',
|
||||
is_active: null // 启用状态筛选
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
// 列表列配置:按照规范排序(系统→核心→详细→配置→时间→操作)
|
||||
listColumns: [
|
||||
// 系统字段
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
|
||||
// 核心业务字段
|
||||
{ title: '题目标题', key: 'question_title', minWidth: 200 },
|
||||
{ title: '题目内容', key: 'question_content', minWidth: 300 },
|
||||
|
||||
// 配置字段
|
||||
{ title: '排序', key: 'sort_order', minWidth: 80, align: 'center' },
|
||||
{
|
||||
title: '启用状态',
|
||||
key: 'is_active',
|
||||
minWidth: 100,
|
||||
align: 'center',
|
||||
render: (h, params) => {
|
||||
const isActive = params.row.is_active;
|
||||
return h('Tag', {
|
||||
props: {
|
||||
color: isActive ? 'success' : 'default'
|
||||
}
|
||||
}, isActive ? '启用' : '禁用');
|
||||
}
|
||||
},
|
||||
|
||||
// 时间字段
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 150 },
|
||||
|
||||
// 操作列
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
// 编辑字段配置:按照规范排序和配置
|
||||
editColumns: [
|
||||
// 核心业务字段
|
||||
{
|
||||
title: '题目标题',
|
||||
key: 'question_title',
|
||||
com: 'Input',
|
||||
disabled: false,
|
||||
required: true,
|
||||
maxlength: 200,
|
||||
placeholder: '请输入题目标题'
|
||||
},
|
||||
{
|
||||
title: '题目内容',
|
||||
key: 'question_content',
|
||||
com: 'TextArea',
|
||||
rows: 4,
|
||||
disabled: false,
|
||||
required: true,
|
||||
maxlength: 1000,
|
||||
placeholder: '请输入题目内容'
|
||||
},
|
||||
{
|
||||
title: '题目数据(JSON)',
|
||||
key: 'question_data',
|
||||
com: 'TextArea',
|
||||
rows: 6,
|
||||
disabled: false,
|
||||
required: true,
|
||||
placeholder: '请输入题目选项数据(JSON格式)'
|
||||
},
|
||||
|
||||
// 配置字段
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort_order',
|
||||
com: 'InputNumber',
|
||||
data_type: 'number',
|
||||
min: 0,
|
||||
max: 9999,
|
||||
disabled: false,
|
||||
required: true,
|
||||
placeholder: '数字越小越靠前'
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
key: 'is_active',
|
||||
com: 'Radio',
|
||||
disabled: false,
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 1, label: '启用' },
|
||||
{ value: 0, label: '禁用' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
ntr_questionsServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
async handleSave({ data, isEdit }) {
|
||||
try {
|
||||
if (isEdit) {
|
||||
await ntr_questionsServer.edit(data);
|
||||
this.$Message.success('编辑成功!');
|
||||
} else {
|
||||
await ntr_questionsServer.add(data);
|
||||
this.$Message.success('新增成功!');
|
||||
}
|
||||
this.query(this.gridOption.param.pageOption.page);
|
||||
} catch (error) {
|
||||
this.$Message.error(error.message || '操作失败!');
|
||||
}
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await ntr_questionsServer.del(row)
|
||||
this.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'question_title',
|
||||
value: '',
|
||||
is_active: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
exportCsv() {
|
||||
ntr_questionsServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '题库管理.csv');
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
261
demo/src/views/ntrp/ntr_records.vue
Normal file
261
demo/src/views/ntrp/ntr_records.vue
Normal file
@@ -0,0 +1,261 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="NTRP等级">
|
||||
<Select v-model="gridOption.param.seachOption.ntrp_level" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option :value="1">1.0</Option>
|
||||
<Option :value="2">2.0</Option>
|
||||
<Option :value="3">3.0</Option>
|
||||
<Option :value="4">4.0</Option>
|
||||
<Option :value="5">5.0</Option>
|
||||
<Option :value="6">6.0</Option>
|
||||
<Option :value="7">7.0</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv" class="ml10">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules" @on-save="handleSave"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import ntr_recordsServer from '@/api/ntrp/ntr_records_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["user_id"] = [{ required: true, type: "number", message: '请填写用户ID', trigger: 'change' }];
|
||||
rules["test_score"] = [{ required: true, type: "number", message: '请填写测试分数', trigger: 'change' }];
|
||||
rules["ntrp_level"] = [{ required: true, type: "number", message: '请填写NTRP等级', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
// 搜索类型:只包含适合文本搜索的字段
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'nickname', value: '用户昵称' }
|
||||
],
|
||||
seachTypePlaceholder: '请选择搜索类型',
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
ntrp_level: null // NTRP等级筛选
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
// 列表列配置:按照规范排序(系统→核心→关联→详细→时间→操作)
|
||||
listColumns: [
|
||||
// 系统字段
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
|
||||
// 关联字段
|
||||
{ title: '用户ID', key: 'user_id', minWidth: 100 },
|
||||
{ title: '用户昵称', key: 'nickname', minWidth: 120 },
|
||||
|
||||
// 核心业务字段
|
||||
{ title: '测试分数', key: 'test_score', minWidth: 100 },
|
||||
{ title: 'NTRP等级', key: 'ntrp_level', minWidth: 100,
|
||||
render: (h, params) => {
|
||||
const level = params.row.ntrp_level;
|
||||
const colors = {
|
||||
1: 'default', 2: 'default', 3: 'blue',
|
||||
4: 'green', 5: 'orange', 6: 'red', 7: 'purple'
|
||||
};
|
||||
return h('Tag', {
|
||||
props: { color: colors[level] || 'default' }
|
||||
}, level ? `${level}.0` : '-');
|
||||
}
|
||||
},
|
||||
|
||||
// 详细信息
|
||||
{ title: '测试结果', key: 'test_result', minWidth: 200 },
|
||||
|
||||
// 时间字段
|
||||
{ title: '测试时间', key: 'test_time', minWidth: 150 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 150 },
|
||||
|
||||
// 操作列
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
// 编辑字段配置:按照规范排序和配置
|
||||
editColumns: [
|
||||
// 关联字段(只读)
|
||||
{
|
||||
title: '用户ID',
|
||||
key: 'user_id',
|
||||
com: 'InputNumber',
|
||||
data_type: 'number',
|
||||
disabled: true, // 用户ID不可修改
|
||||
required: true
|
||||
},
|
||||
|
||||
// 核心业务字段
|
||||
{
|
||||
title: '测试分数',
|
||||
key: 'test_score',
|
||||
com: 'InputNumber',
|
||||
data_type: 'number',
|
||||
min: 0,
|
||||
max: 100,
|
||||
disabled: false,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
title: 'NTRP等级',
|
||||
key: 'ntrp_level',
|
||||
com: 'Select',
|
||||
disabled: false,
|
||||
required: true,
|
||||
source: [
|
||||
{ key: 1, value: '1.0' },
|
||||
{ key: 2, value: '2.0' },
|
||||
{ key: 3, value: '3.0' },
|
||||
{ key: 4, value: '4.0' },
|
||||
{ key: 5, value: '5.0' },
|
||||
{ key: 6, value: '6.0' },
|
||||
{ key: 7, value: '7.0' }
|
||||
]
|
||||
},
|
||||
|
||||
// 时间字段
|
||||
{
|
||||
title: '测试时间',
|
||||
key: 'test_time',
|
||||
com: 'DatePicker',
|
||||
data_type: 'date',
|
||||
type: 'datetime',
|
||||
disabled: false
|
||||
},
|
||||
|
||||
// 详细信息
|
||||
{
|
||||
title: '测试结果',
|
||||
key: 'test_result',
|
||||
com: 'TextArea',
|
||||
rows: 4,
|
||||
disabled: false
|
||||
},
|
||||
|
||||
// 辅助字段
|
||||
{
|
||||
title: '备注',
|
||||
key: 'remark',
|
||||
com: 'TextArea',
|
||||
rows: 3,
|
||||
disabled: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
ntr_recordsServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
async handleSave({ data, isEdit }) {
|
||||
try {
|
||||
if (isEdit) {
|
||||
await ntr_recordsServer.edit(data);
|
||||
this.$Message.success('编辑成功!');
|
||||
} else {
|
||||
await ntr_recordsServer.add(data);
|
||||
this.$Message.success('新增成功!');
|
||||
}
|
||||
this.query(this.gridOption.param.pageOption.page);
|
||||
} catch (error) {
|
||||
this.$Message.error(error.message || '操作失败!');
|
||||
}
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await ntr_recordsServer.del(row)
|
||||
this.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
ntrp_level: null
|
||||
};
|
||||
this.query(1);
|
||||
},
|
||||
exportCsv() {
|
||||
ntr_recordsServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '测试记录.csv');
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
402
demo/src/views/order/frozen_funds.vue
Normal file
402
demo/src/views/order/frozen_funds.vue
Normal file
@@ -0,0 +1,402 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="batchUnfreeze" :disabled="selectedRows.length === 0">
|
||||
批量解冻
|
||||
</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="冻结类型">
|
||||
<Select v-model="gridOption.param.seachOption.freezeType" style="width: 120px" clearable>
|
||||
<Option value="game_deposit">球局定金</Option>
|
||||
<Option value="withdraw">提现冻结</Option>
|
||||
<Option value="risk_control">风控冻结</Option>
|
||||
<Option value="system">系统冻结</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="冻结状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable>
|
||||
<Option value="frozen">冻结中</Option>
|
||||
<Option value="unfrozen">已解冻</Option>
|
||||
<Option value="expired">已过期</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query" @on-selection-change="onSelectionChange"></tables>
|
||||
</div>
|
||||
|
||||
<!-- 批量解冻模态框 -->
|
||||
<Modal v-model="batchUnfreezeModal" title="批量解冻资金" @on-ok="confirmBatchUnfreeze">
|
||||
<Form :model="batchUnfreezeForm" :label-width="100">
|
||||
<FormItem label="解冻原因">
|
||||
<Input v-model="batchUnfreezeForm.reason" type="textarea"
|
||||
placeholder="请输入解冻原因" :rows="3"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="选中记录">
|
||||
<div class="selected-records">
|
||||
<Tag v-for="record in selectedRows" :key="record.id" closable>
|
||||
{{ record.id }} - ¥{{ (record.amount / 100).toFixed(2) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="解冻金额">
|
||||
<div class="total-amount">
|
||||
总计:¥{{ (totalSelectedAmount / 100).toFixed(2) }}
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<!-- 解冻详情模态框 -->
|
||||
<Modal v-model="unfreezeDetailModal" title="解冻详情" width="600">
|
||||
<Form :model="unfreezeDetail" :label-width="100">
|
||||
<FormItem label="用户ID">
|
||||
<span>{{ unfreezeDetail.user_id }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="冻结金额">
|
||||
<span>¥{{ (unfreezeDetail.amount / 100).toFixed(2) }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="冻结原因">
|
||||
<span>{{ unfreezeDetail.freeze_reason }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="冻结时间">
|
||||
<span>{{ unfreezeDetail.freeze_time }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="解冻原因">
|
||||
<Input v-model="unfreezeDetail.unfreeze_reason" type="textarea"
|
||||
placeholder="请输入解冻原因" :rows="3"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer">
|
||||
<Button @click="unfreezeDetailModal = false">取消</Button>
|
||||
<Button type="primary" @click="confirmUnfreeze">确认解冻</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import frozenFundsServer from '@/api/order/frozen_funds_server.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
selectedRows: [],
|
||||
batchUnfreezeModal: false,
|
||||
batchUnfreezeForm: {
|
||||
reason: ''
|
||||
},
|
||||
unfreezeDetailModal: false,
|
||||
unfreezeDetail: {},
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
freezeType: '',
|
||||
status: ''
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: {}
|
||||
},
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'transaction_id', value: '交易ID' },
|
||||
{ key: 'related_id', value: '关联ID' },
|
||||
{ key: 'freeze_reason', value: '冻结原因' }
|
||||
],
|
||||
listColumns: [
|
||||
{
|
||||
type: 'selection',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id'
|
||||
},
|
||||
{
|
||||
title: '用户ID',
|
||||
key: 'user_id'
|
||||
},
|
||||
{
|
||||
title: '冻结金额',
|
||||
key: 'amount',
|
||||
render: (h, params) => {
|
||||
return h('span', { style: { color: '#f56c6c' } }, `¥${(params.row.amount / 100).toFixed(2)}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '冻结类型',
|
||||
key: 'freeze_type',
|
||||
render: (h, params) => {
|
||||
const typeMap = {
|
||||
'game_deposit': { text: '球局定金', color: 'blue' },
|
||||
'withdraw': { text: '提现冻结', color: 'orange' },
|
||||
'risk_control': { text: '风控冻结', color: 'red' },
|
||||
'system': { text: '系统冻结', color: 'gray' }
|
||||
}
|
||||
const type = typeMap[params.row.freeze_type] || { text: params.row.freeze_type, color: 'default' }
|
||||
return h('Tag', { props: { color: type.color } }, type.text)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '冻结状态',
|
||||
key: 'status',
|
||||
render: (h, params) => {
|
||||
const statusMap = {
|
||||
'frozen': { text: '冻结中', color: 'red' },
|
||||
'unfrozen': { text: '已解冻', color: 'green' },
|
||||
'expired': { text: '已过期', color: 'gray' }
|
||||
}
|
||||
const status = statusMap[params.row.status] || { text: params.row.status, color: 'default' }
|
||||
return h('Tag', { props: { color: status.color } }, status.text)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '冻结原因',
|
||||
key: 'freeze_reason',
|
||||
render: (h, params) => {
|
||||
return h('span', {
|
||||
attrs: { title: params.row.freeze_reason },
|
||||
style: {
|
||||
display: 'block',
|
||||
maxWidth: '180px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}, params.row.freeze_reason)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '冻结时间',
|
||||
key: 'freeze_time'
|
||||
},
|
||||
{
|
||||
title: '解冻时间',
|
||||
key: 'unfreeze_time',
|
||||
render: (h, params) => {
|
||||
return h('span', params.row.unfreeze_time || '-')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '解冻',
|
||||
type: 'primary',
|
||||
disabled: params.row.status !== 'frozen',
|
||||
click: () => {
|
||||
this.showUnfreezeDetail(params.row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '详情',
|
||||
type: 'info',
|
||||
click: () => {
|
||||
this.viewDetail(params.row)
|
||||
}
|
||||
}
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key)
|
||||
return selected ? selected.value : '请选择搜索类型'
|
||||
},
|
||||
totalSelectedAmount() {
|
||||
return this.selectedRows.reduce((total, row) => total + row.amount, 0)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1)
|
||||
},
|
||||
methods: {
|
||||
async query(page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
|
||||
// 构建查询参数
|
||||
const params = {
|
||||
page: page,
|
||||
pageSize: this.gridOption.param.pageOption.pageSize,
|
||||
seachOption: this.gridOption.param.seachOption
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用API获取冻结资金列表
|
||||
const res = await frozenFundsServer.getFrozenFundsList(params)
|
||||
if (res.code === 0) {
|
||||
this.gridOption.data = res.data.rows || []
|
||||
this.gridOption.param.pageOption.total = res.data.total || 0
|
||||
} else {
|
||||
this.$Message.error(res.message || '获取冻结资金列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取冻结资金列表失败:', error)
|
||||
this.$Message.error('获取冻结资金列表失败')
|
||||
}
|
||||
},
|
||||
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
freezeType: '',
|
||||
status: ''
|
||||
}
|
||||
this.query(1)
|
||||
},
|
||||
|
||||
onSelectionChange(selection) {
|
||||
this.selectedRows = selection
|
||||
},
|
||||
|
||||
batchUnfreeze() {
|
||||
if (this.selectedRows.length === 0) {
|
||||
this.$Message.warning('请先选择要解冻的记录')
|
||||
return
|
||||
}
|
||||
this.batchUnfreezeModal = true
|
||||
},
|
||||
|
||||
async confirmBatchUnfreeze() {
|
||||
if (!this.batchUnfreezeForm.reason) {
|
||||
this.$Message.error('请输入解冻原因')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const params = {
|
||||
ids: this.selectedRows.map(row => row.id),
|
||||
reason: this.batchUnfreezeForm.reason
|
||||
}
|
||||
|
||||
const res = await frozenFundsServer.batchUnfreezeFunds(params)
|
||||
if (res.code === 0) {
|
||||
this.$Message.success(res.message || `成功解冻 ${this.selectedRows.length} 条记录`)
|
||||
this.batchUnfreezeModal = false
|
||||
this.batchUnfreezeForm = { reason: '' }
|
||||
this.selectedRows = []
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '批量解冻失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('批量解冻失败:', error)
|
||||
this.$Message.error('批量解冻失败')
|
||||
}
|
||||
},
|
||||
|
||||
showUnfreezeDetail(row) {
|
||||
this.unfreezeDetail = { ...row }
|
||||
this.unfreezeDetailModal = true
|
||||
},
|
||||
|
||||
async confirmUnfreeze() {
|
||||
if (!this.unfreezeDetail.unfreeze_reason) {
|
||||
this.$Message.error('请输入解冻原因')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const params = {
|
||||
id: this.unfreezeDetail.id,
|
||||
unfreeze_reason: this.unfreezeDetail.unfreeze_reason
|
||||
}
|
||||
|
||||
const res = await frozenFundsServer.unfreezeFund(params)
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('资金解冻成功')
|
||||
this.unfreezeDetailModal = false
|
||||
this.unfreezeDetail = {}
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '解冻失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解冻失败:', error)
|
||||
this.$Message.error('解冻失败')
|
||||
}
|
||||
},
|
||||
|
||||
async viewDetail(row) {
|
||||
try {
|
||||
const res = await frozenFundsServer.getFrozenFundDetail({ id: row.id })
|
||||
if (res.code === 0) {
|
||||
const detail = res.data
|
||||
this.$Modal.info({
|
||||
title: '冻结详情',
|
||||
content: `
|
||||
<div>
|
||||
<p><strong>冻结ID:</strong> ${detail.id}</p>
|
||||
<p><strong>用户ID:</strong> ${detail.user_id}</p>
|
||||
<p><strong>用户昵称:</strong> ${detail.user_nickname || '未知'}</p>
|
||||
<p><strong>冻结金额:</strong> ¥${(detail.amount / 100).toFixed(2)}</p>
|
||||
<p><strong>冻结类型:</strong> ${detail.freeze_type}</p>
|
||||
<p><strong>冻结状态:</strong> ${detail.status}</p>
|
||||
<p><strong>冻结原因:</strong> ${detail.freeze_reason}</p>
|
||||
<p><strong>冻结时间:</strong> ${detail.freeze_time}</p>
|
||||
${detail.unfreeze_time ? `<p><strong>解冻时间:</strong> ${detail.unfreeze_time}</p>` : ''}
|
||||
</div>
|
||||
`
|
||||
})
|
||||
} else {
|
||||
this.$Message.error(res.message || '获取详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取详情失败:', error)
|
||||
this.$Message.error('获取详情失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.selected-records {
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #dcdee2;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
592
demo/src/views/order/pay_orders.vue
Normal file
592
demo/src/views/order/pay_orders.vue
Normal file
@@ -0,0 +1,592 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddModal">新增订单</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="订单状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable>
|
||||
<Option :value="0">待支付</Option>
|
||||
<Option :value="1">已支付</Option>
|
||||
<Option :value="2">已结束</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="订单类型">
|
||||
<Select v-model="gridOption.param.seachOption.order_type" style="width: 120px" clearable>
|
||||
<Option value="game_deposit">球局定金</Option>
|
||||
<Option value="venue_booking">场地预订</Option>
|
||||
<Option value="recharge">充值</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="default" @click="exportOrders">导出订单</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑订单模态框 -->
|
||||
<Modal v-model="orderModal" :title="orderModalTitle" width="800" @on-ok="saveOrder">
|
||||
<Form :model="orderForm" :rules="orderRules" ref="orderForm" :label-width="100">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="订单号" prop="order_no">
|
||||
<Input v-model="orderForm.order_no" placeholder="请输入订单号"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="用户ID" prop="user_id">
|
||||
<Input v-model="orderForm.user_id" placeholder="请输入用户ID"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="业务类型" prop="order_type">
|
||||
<Select v-model="orderForm.order_type" placeholder="请选择业务类型">
|
||||
<Option value="game_deposit">球局定金</Option>
|
||||
<Option value="venue_booking">场地预订</Option>
|
||||
<Option value="recharge">充值</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="业务ID" prop="business_id">
|
||||
<Input v-model="orderForm.business_id" placeholder="请输入业务ID"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="订单金额" prop="amount">
|
||||
<Input v-model="orderForm.amount" placeholder="请输入金额(分)" type="number"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="订单状态" prop="order_status">
|
||||
<Select v-model="orderForm.order_status" placeholder="请选择订单状态">
|
||||
<Option :value="0">待支付</Option>
|
||||
<Option :value="1">已支付</Option>
|
||||
<Option :value="2">已结束</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="支付方式" prop="payment_method">
|
||||
<Select v-model="orderForm.payment_method" placeholder="请选择支付方式">
|
||||
<Option value="wechat">微信支付</Option>
|
||||
<Option value="alipay">支付宝</Option>
|
||||
<Option value="balance">余额支付</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="退款状态" prop="refund_status">
|
||||
<Select v-model="orderForm.refund_status" placeholder="请选择退款状态">
|
||||
<Option :value="0">无退款</Option>
|
||||
<Option :value="1">退款中</Option>
|
||||
<Option :value="2">已退款</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<FormItem label="订单描述" prop="description">
|
||||
<Input v-model="orderForm.description" type="textarea"
|
||||
placeholder="请输入订单描述" :rows="3"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="备注" prop="remark">
|
||||
<Input v-model="orderForm.remark" type="textarea"
|
||||
placeholder="请输入备注" :rows="2"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<!-- 订单详情模态框 -->
|
||||
<Modal v-model="detailModal" title="订单详情" width="800">
|
||||
<div v-if="orderDetail">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>订单ID:</label>
|
||||
<span>{{ orderDetail.id }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>订单号:</label>
|
||||
<span>{{ orderDetail.order_no }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>用户ID:</label>
|
||||
<span>{{ orderDetail.user_id }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>业务类型:</label>
|
||||
<Tag :color="getBusinessTypeColor(orderDetail.order_type)">
|
||||
{{ getBusinessTypeText(orderDetail.order_type) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>订单金额:</label>
|
||||
<span class="amount-text">¥{{ (orderDetail.amount / 100).toFixed(2) }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>订单状态:</label>
|
||||
<Tag :color="getStatusColor(orderDetail.order_status)">
|
||||
{{ getStatusText(orderDetail.order_status) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>支付方式:</label>
|
||||
<span>{{ getPaymentMethodText(orderDetail.payment_method) }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>退款状态:</label>
|
||||
<Tag :color="getRefundStatusColor(orderDetail.refund_status)">
|
||||
{{ getRefundStatusText(orderDetail.refund_status) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>创建时间:</label>
|
||||
<span>{{ orderDetail.create_time }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>支付时间:</label>
|
||||
<span>{{ orderDetail.pay_time || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16" v-if="orderDetail.description">
|
||||
<Col span="24">
|
||||
<div class="detail-item">
|
||||
<label>订单描述:</label>
|
||||
<span>{{ orderDetail.description }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16" v-if="orderDetail.remark">
|
||||
<Col span="24">
|
||||
<div class="detail-item">
|
||||
<label>备注:</label>
|
||||
<span>{{ orderDetail.remark }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import paymentOrdersServer from '@/api/order/payment_orders_server.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
orderModal: false,
|
||||
orderModalTitle: '',
|
||||
orderForm: {
|
||||
order_no: '',
|
||||
user_id: '',
|
||||
order_type: '',
|
||||
business_id: '',
|
||||
amount: '',
|
||||
order_status: 0,
|
||||
payment_method: '',
|
||||
refund_status: 0,
|
||||
description: '',
|
||||
remark: ''
|
||||
},
|
||||
orderRules: {
|
||||
order_no: [{ required: true, message: '请输入订单号', trigger: 'blur' }],
|
||||
user_id: [{ required: true, message: '请输入用户ID', trigger: 'blur' }],
|
||||
order_type: [{ required: true, message: '请选择业务类型', trigger: 'change' }],
|
||||
amount: [{ required: true, message: '请输入订单金额', trigger: 'blur' }],
|
||||
order_status: [{ required: true, message: '请选择订单状态', trigger: 'change' }]
|
||||
},
|
||||
detailModal: false,
|
||||
orderDetail: null,
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'order_no',
|
||||
value: '',
|
||||
status: '',
|
||||
order_type: ''
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: {}
|
||||
},
|
||||
seachTypes: [
|
||||
{ key: 'order_no', value: '订单号' },
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'business_id', value: '业务ID' },
|
||||
{ key: 'description', value: '订单描述' }
|
||||
],
|
||||
listColumns: [
|
||||
{
|
||||
title: '订单ID',
|
||||
key: 'id',
|
||||
minWidth: 80
|
||||
},
|
||||
{
|
||||
title: '订单号',
|
||||
key: 'order_no',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
title: '用户ID',
|
||||
key: 'user_id',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '业务类型',
|
||||
key: 'order_type',
|
||||
minWidth: 120,
|
||||
render: (h, params) => {
|
||||
return h('Tag', { props: { color: this.getBusinessTypeColor(params.row.order_type) } },
|
||||
this.getBusinessTypeText(params.row.order_type))
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '业务ID',
|
||||
key: 'business_id',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
key: 'amount',
|
||||
minWidth: 120
|
||||
},
|
||||
{
|
||||
title: '订单状态',
|
||||
key: 'order_status',
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h('Tag', { props: { color: this.getStatusColor(params.row.order_status) } },
|
||||
this.getStatusText(params.row.order_status))
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
key: 'payment_method',
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h('span', this.getPaymentMethodText(params.row.payment_method))
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '退款状态',
|
||||
key: 'refund_status',
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h('Tag', { props: { color: this.getRefundStatusColor(params.row.refund_status) } },
|
||||
this.getRefundStatusText(params.row.refund_status))
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'create_time',
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 250,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.editOrder(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '详情',
|
||||
type: 'info',
|
||||
click: () => {
|
||||
this.viewDetail(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '取消',
|
||||
type: 'warning',
|
||||
click: () => {
|
||||
this.cancelOrder(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key)
|
||||
return selected ? selected.value : '请选择搜索类型'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1)
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
if (page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
}
|
||||
|
||||
paymentOrdersServer.getPaymentOrdersList(this.gridOption.param).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.gridOption.data = res.data.rows || res.data
|
||||
this.gridOption.param.pageOption.total = res.data.count || res.data.total || 0
|
||||
} else {
|
||||
this.$Message.error(res.message || '查询失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$Message.error('查询失败: ' + error.message)
|
||||
})
|
||||
},
|
||||
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'order_no',
|
||||
value: '',
|
||||
status: '',
|
||||
order_type: ''
|
||||
}
|
||||
this.query(1)
|
||||
},
|
||||
|
||||
showAddModal() {
|
||||
this.orderForm = {
|
||||
order_no: '',
|
||||
user_id: '',
|
||||
order_type: '',
|
||||
business_id: '',
|
||||
amount: '',
|
||||
order_status: 0,
|
||||
payment_method: '',
|
||||
refund_status: 0,
|
||||
description: '',
|
||||
remark: ''
|
||||
}
|
||||
this.orderModalTitle = '新增订单'
|
||||
this.orderModal = true
|
||||
},
|
||||
|
||||
editOrder(row) {
|
||||
this.orderForm = { ...row }
|
||||
this.orderModalTitle = '编辑订单'
|
||||
this.orderModal = true
|
||||
},
|
||||
|
||||
saveOrder() {
|
||||
this.$refs.orderForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.orderForm.id) {
|
||||
// 编辑订单
|
||||
paymentOrdersServer.updatePaymentOrder(this.orderForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('订单更新成功')
|
||||
this.orderModal = false
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '更新失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$Message.error('更新失败: ' + error.message)
|
||||
})
|
||||
} else {
|
||||
// 新增订单
|
||||
paymentOrdersServer.addPaymentOrder(this.orderForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('订单创建成功')
|
||||
this.orderModal = false
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '创建失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$Message.error('创建失败: ' + error.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
cancelOrder(row) {
|
||||
this.$Modal.confirm({
|
||||
title: '取消订单',
|
||||
content: `确定要取消订单 ${row.order_no} 吗?`,
|
||||
onOk: async () => {
|
||||
paymentOrdersServer.cancelPaymentOrder(row.id).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('订单已取消')
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '取消失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$Message.error('取消失败: ' + error.message)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
viewDetail(row) {
|
||||
this.orderDetail = row
|
||||
this.detailModal = true
|
||||
},
|
||||
|
||||
exportOrders() {
|
||||
paymentOrdersServer.exportPaymentOrders(this.gridOption.param).then(res => {
|
||||
if (res.code === 0) {
|
||||
funTool.downloadFile(res, '订单列表.csv')
|
||||
} else {
|
||||
this.$Message.error(res.message || '导出失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$Message.error('导出失败: ' + error.message)
|
||||
})
|
||||
},
|
||||
|
||||
getBusinessTypeColor(type) {
|
||||
const colorMap = {
|
||||
'game_deposit': 'blue',
|
||||
'venue_booking': 'green',
|
||||
'recharge': 'orange'
|
||||
}
|
||||
return colorMap[type] || 'default'
|
||||
},
|
||||
|
||||
getBusinessTypeText(type) {
|
||||
const textMap = {
|
||||
'game_deposit': '球局定金',
|
||||
'venue_booking': '场地预订',
|
||||
'recharge': '充值'
|
||||
}
|
||||
return textMap[type] || type
|
||||
},
|
||||
|
||||
getStatusColor(status) {
|
||||
const colorMap = {
|
||||
0: 'orange', // 待支付
|
||||
1: 'green', // 已支付
|
||||
2: 'blue' // 已结束
|
||||
}
|
||||
return colorMap[status] || 'default'
|
||||
},
|
||||
|
||||
getStatusText(status) {
|
||||
const textMap = {
|
||||
0: '待支付',
|
||||
1: '已支付',
|
||||
2: '已结束'
|
||||
}
|
||||
return textMap[status] || status
|
||||
},
|
||||
|
||||
getPaymentMethodText(method) {
|
||||
const textMap = {
|
||||
'wechat': '微信支付',
|
||||
'alipay': '支付宝',
|
||||
'balance': '余额支付'
|
||||
}
|
||||
return textMap[method] || method
|
||||
},
|
||||
|
||||
getRefundStatusColor(status) {
|
||||
const colorMap = {
|
||||
0: 'default', // 无退款
|
||||
1: 'orange', // 退款中
|
||||
2: 'green' // 已退款
|
||||
}
|
||||
return colorMap[status] || 'default'
|
||||
},
|
||||
|
||||
getRefundStatusText(status) {
|
||||
const textMap = {
|
||||
0: '无退款',
|
||||
1: '退款中',
|
||||
2: '已退款'
|
||||
}
|
||||
return textMap[status] || status
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.detail-item label {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.amount-text {
|
||||
color: #f56c6c;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
234
demo/src/views/order/transfer_details.vue
Normal file
234
demo/src/views/order/transfer_details.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="明细状态">
|
||||
<Select v-model="gridOption.param.seachOption.detail_status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="WAIT_USER_CONFIRM">处理中</Option>
|
||||
<Option value="SUCCESS">成功</Option>
|
||||
<Option value="FAIL">失败</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import transfer_detailsServer from '@/api/order/transfer_details_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["out_bill_no"] = [{ required: true, message: '请填写商户明细号', trigger: 'blur' }];
|
||||
rules["openid"] = [{ required: true, message: '请填写收款用户openid', trigger: 'blur' }];
|
||||
rules["transfer_amount"] = [{ required: true, type: "number", message: '请填写转账金额', trigger: 'change' }];
|
||||
rules["transfer_remark"] = [{ required: true, message: '请填写转账备注', trigger: 'blur' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: 'out_bill_no', value: '商户明细号' },
|
||||
{ key: 'transfer_bill_no', value: '微信交易号' },
|
||||
{ key: 'openid', value: '收款用户openid' }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'out_bill_no',
|
||||
value: '',
|
||||
detail_status: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id' },
|
||||
{ title: '商户明细号', key: 'out_bill_no' },
|
||||
{ title: '微信交易号', key: 'transfer_bill_no' },
|
||||
{ title: '收款用户openid', key: 'openid' },
|
||||
{ title: '收款用户昵称', key: 'user_nickname' },
|
||||
{
|
||||
title: '转账金额',
|
||||
key: 'transfer_amount',
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
return h('span', { style: { color: '#67c23a', fontWeight: 'bold' } },
|
||||
`¥${(params.row.transfer_amount / 100).toFixed(2)}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '转账备注',
|
||||
key: 'transfer_remark',
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
return h('span', {
|
||||
attrs: { title: params.row.transfer_remark },
|
||||
style: {
|
||||
display: 'block',
|
||||
maxWidth: '150px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
}, params.row.transfer_remark)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '明细状态',
|
||||
key: 'detail_status',
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
const statusMap = {
|
||||
'WAIT_USER_CONFIRM': { text: '处理中', color: 'orange' },
|
||||
'SUCCESS': { text: '成功', color: 'green' },
|
||||
'FAIL': { text: '失败', color: 'red' }
|
||||
}
|
||||
const status = statusMap[params.row.detail_status] || { text: params.row.detail_status, color: 'default' }
|
||||
return h('Tag', { props: { color: status.color } }, status.text)
|
||||
}
|
||||
},
|
||||
{ title: '失败原因', key: 'fail_reason' },
|
||||
{ title: '创建时间', key: 'create_time' },
|
||||
{ title: '更新时间', key: 'update_time' },
|
||||
{ title: '完成时间', key: 'finish_time' },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '商户明细号', key: 'out_bill_no', type: 'text', required: true },
|
||||
{ title: '微信交易号', key: 'transfer_bill_no', type: 'text' },
|
||||
{ title: '收款用户openid', key: 'openid', type: 'text', required: true },
|
||||
{ title: '收款用户姓名', key: 'user_name', type: 'text' },
|
||||
{ title: '转账金额(分)', key: 'transfer_amount', type: 'number', required: true },
|
||||
{ title: '转账备注', key: 'transfer_remark', type: 'textarea', required: true },
|
||||
{ title: '明细状态', key: 'detail_status', type: 'select', options: [
|
||||
{ value: 'WAIT_USER_CONFIRM', label: '处理中' },
|
||||
{ value: 'SUCCESS', label: '成功' },
|
||||
{ value: 'FAIL', label: '失败' }
|
||||
]},
|
||||
{ title: '失败原因', key: 'fail_reason', type: 'textarea' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
async query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
try {
|
||||
const res = await transfer_detailsServer.page(this.gridOption.param);
|
||||
if (res.code === 0) {
|
||||
this.gridOption.data = res.data.rows || [];
|
||||
this.gridOption.param.pageOption.total = res.data.count || 0;
|
||||
} else {
|
||||
this.$Message.error(res.message || '获取转账详情失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取转账详情失败:', error);
|
||||
this.$Message.error('获取转账详情失败');
|
||||
}
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
try {
|
||||
const res = await transfer_detailsServer.del(row);
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('删除成功!');
|
||||
this.query(1);
|
||||
} else {
|
||||
this.$Message.error(res.message || '删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error);
|
||||
this.$Message.error('删除失败');
|
||||
}
|
||||
})
|
||||
},
|
||||
async exportCsv() {
|
||||
try {
|
||||
const res = await transfer_detailsServer.exportCsv(this.gridOption.param);
|
||||
if (res.code === 0) {
|
||||
funTool.downloadFile(res.data, '转账详情.csv');
|
||||
} else {
|
||||
this.$Message.error(res.message || '导出失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error);
|
||||
this.$Message.error('导出失败');
|
||||
}
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'out_bill_no',
|
||||
value: '',
|
||||
detail_status: null
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
},
|
||||
editColumns() {
|
||||
return this.gridOption.columns.filter(p => p.is_show_edit === 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
286
demo/src/views/order/wallet_transactions.vue
Normal file
286
demo/src/views/order/wallet_transactions.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="交易类型">
|
||||
<Select v-model="gridOption.param.seachOption.transaction_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="recharge">充值</Option>
|
||||
<Option value="withdraw">提现</Option>
|
||||
<Option value="game_deposit">球局定金</Option>
|
||||
<Option value="game_refund">球局退款</Option>
|
||||
<Option value="transfer">转账</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="交易状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="pending">待处理</Option>
|
||||
<Option value="success">成功</Option>
|
||||
<Option value="failed">失败</Option>
|
||||
<Option value="cancelled">已取消</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"></editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import menuServer from '@/api/system_high/menuServer.js'
|
||||
import walletTransactionsServer from '@/api/ball/wallet_transactions_server.js'
|
||||
|
||||
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["status"] = [{ required: true, message: '请选择状态' }];
|
||||
rules["remark"] = [{ message: '请填写备注' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: "user_id", value: "用户ID" },
|
||||
{ key: "nickname", value: "用户昵称" },
|
||||
{ key: "transaction_no", value: "交易流水号" }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: "user_id",
|
||||
value: "",
|
||||
transaction_type: null,
|
||||
status: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
rules,
|
||||
columns: [
|
||||
{ key: 'id', title: 'ID', minWidth: 80, is_show_edit: 0 },
|
||||
{
|
||||
key: "user_id",
|
||||
title: "用户",
|
||||
disabled: true,
|
||||
is_show_edit: 0,
|
||||
is_show_list: 1,
|
||||
com: "Input",
|
||||
render: (h, params) => {
|
||||
const userInfo = params.row.user_info;
|
||||
if (userInfo && userInfo.nickname) {
|
||||
return h('div', [
|
||||
h('img', {
|
||||
attrs: {
|
||||
src: userInfo.avatar_url || '/default-avatar.png',
|
||||
alt: userInfo.nickname,
|
||||
title: userInfo.nickname
|
||||
},
|
||||
style: {
|
||||
minWidth: 80,
|
||||
height: '24px',
|
||||
borderRadius: '50%',
|
||||
marginRight: '8px',
|
||||
verticalAlign: 'middle'
|
||||
}
|
||||
}),
|
||||
h('span', { style: { verticalAlign: 'middle' } }, userInfo.nickname)
|
||||
]);
|
||||
}
|
||||
return h('span', `用户ID: ${params.row.user_id}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "transaction_type",
|
||||
title: "交易类型",
|
||||
disabled: true,
|
||||
is_show_edit: 0,
|
||||
is_show_list: 1,
|
||||
com: "Select",
|
||||
render: (h, params) => {
|
||||
const freezeAction = params.row.freeze_action;
|
||||
let typeText = '';
|
||||
let color = 'default';
|
||||
|
||||
if (params.row.transaction_type === 'income') {
|
||||
if (freezeAction === 'freeze') {
|
||||
typeText = '收入(冻结)';
|
||||
color = 'orange';
|
||||
} else if (freezeAction === 'unfreeze') {
|
||||
typeText = '收入(解冻)';
|
||||
color = 'green';
|
||||
} else {
|
||||
typeText = '收入';
|
||||
color = 'green';
|
||||
}
|
||||
} else if (params.row.transaction_type === 'expense') {
|
||||
if (freezeAction === 'unfreeze') {
|
||||
typeText = '支出(解冻)';
|
||||
color = 'purple';
|
||||
} else {
|
||||
typeText = '支出';
|
||||
color = 'red';
|
||||
}
|
||||
} else {
|
||||
typeText = params.row.transaction_type || '未知';
|
||||
}
|
||||
|
||||
return h('Tag', { props: { color: color } }, typeText);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "amount",
|
||||
title: "交易金额",
|
||||
disabled: true,
|
||||
is_show_edit: 0,
|
||||
is_show_list: 1,
|
||||
com: "InputNumber",
|
||||
render: (h, params) => {
|
||||
const amount = parseFloat(params.row.amount || 0);
|
||||
return h('span', {
|
||||
style: {
|
||||
color: amount > 0 ? '#19be6b' : '#ed4014',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}, `${amount > 0 ? '+' : ''}¥${amount.toFixed(2)}`);
|
||||
}
|
||||
},
|
||||
|
||||
{ key: "description", title: "交易描述", disabled: true, is_show_edit: 0, is_show_list: 1, com: "Input" },
|
||||
{
|
||||
key: "related_id",
|
||||
title: "关联ID",
|
||||
disabled: true,
|
||||
is_show_edit: 0,
|
||||
is_show_list: 1,
|
||||
com: "Input",
|
||||
render: (h, params) => {
|
||||
const relatedId = params.row.related_id;
|
||||
if (relatedId) {
|
||||
return h('span', relatedId);
|
||||
}
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '-');
|
||||
}
|
||||
},
|
||||
{ key: "create_time", title: "交易时间", disabled: true, is_show_edit: 0, is_show_list: 1, com: "DatePicker" }
|
||||
],
|
||||
data: [],
|
||||
seachTypes: this.seachTypes,
|
||||
apiServer: walletTransactionsServer,
|
||||
showAdd: false,
|
||||
showEdit: true,
|
||||
showDel: false,
|
||||
showExport: true
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '用户', key: 'user_id', minWidth: 120 },
|
||||
{ title: '交易类型', key: 'transaction_type', minWidth: 120 },
|
||||
{ title: '交易金额', key: 'amount', minWidth: 120 },
|
||||
{ title: '交易描述', key: 'description', minWidth: 200 },
|
||||
{ title: '关联ID', key: 'related_id', minWidth: 120 },
|
||||
{ title: '交易时间', key: 'create_time', minWidth: 150 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
}
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '状态', key: 'status', type: 'select', required: true,
|
||||
source: [
|
||||
{ key: 'pending', value: '待处理' },
|
||||
{ key: 'completed', value: '已完成' },
|
||||
{ key: 'failed', value: '失败' }
|
||||
]
|
||||
},
|
||||
{ title: '备注', key: 'remark', type: 'textarea' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
walletTransactionsServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
async showAddWarp() {
|
||||
// 交易记录不支持手动新增
|
||||
this.$Message.warning('交易记录由系统自动生成,无需手动添加');
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
async showDelWarp(row) {
|
||||
// 交易记录不支持删除
|
||||
this.$Message.warning('交易记录不支持删除操作');
|
||||
},
|
||||
exportCsv() {
|
||||
walletTransactionsServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '交易记录.csv');
|
||||
});
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
transaction_type: null,
|
||||
status: null
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
},
|
||||
editColumns() {
|
||||
let editTempColumns = this.gridOption.columns.filter(p => p.is_show_edit === 1)
|
||||
return editTempColumns
|
||||
},
|
||||
listColumns() {
|
||||
let listTempColumns = this.gridOption.columns.filter(p => p.is_show_list === 1)
|
||||
return listTempColumns
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
513
demo/src/views/order/wch_wallets.vue
Normal file
513
demo/src/views/order/wch_wallets.vue
Normal file
@@ -0,0 +1,513 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddModal">新增钱包</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="余额范围">
|
||||
<InputNumber v-model="gridOption.param.seachOption.minBalance" placeholder="最小余额"
|
||||
style="width: 100px"></InputNumber>
|
||||
<span class="ml5 mr5">-</span>
|
||||
<InputNumber v-model="gridOption.param.seachOption.maxBalance" placeholder="最大余额"
|
||||
style="width: 100px"></InputNumber>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="default" @click="exportWallets">导出钱包</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑钱包模态框 -->
|
||||
<Modal v-model="walletModal" :title="walletModalTitle" width="600" @on-ok="saveWallet">
|
||||
<Form :model="walletForm" :rules="walletRules" ref="walletForm" :label-width="100">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="用户ID" prop="user_id">
|
||||
<Input v-model="walletForm.user_id" placeholder="请输入用户ID"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="可用余额" prop="balance">
|
||||
<Input v-model="walletForm.balance" placeholder="请输入可用余额(分)" type="number"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<FormItem label="冻结余额" prop="frozen_balance">
|
||||
<Input v-model="walletForm.frozen_balance" placeholder="请输入冻结余额(分)" type="number"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<FormItem label="总收入" prop="total_income">
|
||||
<Input v-model="walletForm.total_income" placeholder="请输入总收入(分)" type="number"></Input>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<FormItem label="钱包密码" prop="password">
|
||||
<Input v-model="walletForm.password" type="password" placeholder="请输入钱包密码"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="备注" prop="remark">
|
||||
<Input v-model="walletForm.remark" type="textarea" placeholder="请输入备注" :rows="3"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<!-- 钱包详情模态框 -->
|
||||
<Modal v-model="detailModal" title="钱包详情" width="800">
|
||||
<div v-if="walletDetail">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>钱包ID:</label>
|
||||
<span>{{ walletDetail.id }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>用户ID:</label>
|
||||
<span>{{ walletDetail.user_id }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>总余额:</label>
|
||||
<span class="amount-text">¥{{ (walletDetail.total_balance / 100).toFixed(2) }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>可用余额:</label>
|
||||
<span class="amount-text available">¥{{ (walletDetail.balance / 100).toFixed(2) }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>冻结余额:</label>
|
||||
<span class="amount-text frozen">¥{{ (walletDetail.frozen_balance / 100).toFixed(2) }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>总收入:</label>
|
||||
<span class="amount-text income">¥{{ (walletDetail.total_income / 100).toFixed(2) }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>创建时间:</label>
|
||||
<span>{{ walletDetail.create_time }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="detail-item">
|
||||
<label>更新时间:</label>
|
||||
<span>{{ walletDetail.last_modify_time }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row :gutter="16" v-if="walletDetail.remark">
|
||||
<Col span="24">
|
||||
<div class="detail-item">
|
||||
<label>备注:</label>
|
||||
<span>{{ walletDetail.remark }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 钱包操作模态框 -->
|
||||
<Modal v-model="operationModal" title="钱包操作" width="500" @on-ok="confirmOperation">
|
||||
<Form :model="operationForm" :rules="operationRules" ref="operationForm" :label-width="100">
|
||||
<FormItem label="操作类型" prop="type">
|
||||
<RadioGroup v-model="operationForm.type">
|
||||
<Radio label="recharge">充值</Radio>
|
||||
<Radio label="withdraw">提现</Radio>
|
||||
<Radio label="freeze">冻结</Radio>
|
||||
<Radio label="unfreeze">解冻</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="操作金额" prop="amount">
|
||||
<Input v-model="operationForm.amount" placeholder="请输入金额(分)" type="number"></Input>
|
||||
</FormItem>
|
||||
<FormItem label="操作原因" prop="reason">
|
||||
<Input v-model="operationForm.reason" type="textarea" placeholder="请输入操作原因" :rows="3"></Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import wchWalletsServer from '@/api/order/wch_wallets_server.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
walletModal: false,
|
||||
walletModalTitle: '',
|
||||
walletForm: {
|
||||
user_id: '',
|
||||
balance: '',
|
||||
frozen_balance: '',
|
||||
total_income: '',
|
||||
password: '',
|
||||
remark: ''
|
||||
},
|
||||
walletRules: {
|
||||
user_id: [{ required: true, message: '请输入用户ID', trigger: 'blur' }],
|
||||
balance: [{ required: true, message: '请输入可用余额', trigger: 'blur' }],
|
||||
frozen_balance: [{ required: true, message: '请输入冻结余额', trigger: 'blur' }]
|
||||
},
|
||||
detailModal: false,
|
||||
walletDetail: null,
|
||||
operationModal: false,
|
||||
operationForm: {
|
||||
type: '',
|
||||
amount: '',
|
||||
reason: ''
|
||||
},
|
||||
operationRules: {
|
||||
type: [{ required: true, message: '请选择操作类型', trigger: 'change' }],
|
||||
amount: [{ required: true, message: '请输入操作金额', trigger: 'blur' }],
|
||||
reason: [{ required: true, message: '请输入操作原因', trigger: 'blur' }]
|
||||
},
|
||||
currentWallet: null,
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
minBalance: null,
|
||||
maxBalance: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: {}
|
||||
},
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'id', value: '钱包ID' },
|
||||
{ key: 'remark', value: '备注' }
|
||||
],
|
||||
listColumns: [
|
||||
{
|
||||
title: '钱包ID',
|
||||
key: 'id'
|
||||
},
|
||||
{
|
||||
title: '用户ID',
|
||||
key: 'user_id'
|
||||
},
|
||||
{
|
||||
title: '可用余额',
|
||||
key: 'balance',
|
||||
render: (h, params) => {
|
||||
return h('span', { style: { color: '#67c23a', fontWeight: 'bold' } },
|
||||
`¥${(params.row.balance / 100).toFixed(2)}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '冻结余额',
|
||||
key: 'frozen_balance',
|
||||
render: (h, params) => {
|
||||
return h('span', { style: { color: '#e6a23c', fontWeight: 'bold' } },
|
||||
`¥${(params.row.frozen_balance / 100).toFixed(2)}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '总余额',
|
||||
key: 'total_balance',
|
||||
render: (h, params) => {
|
||||
const total = params.row.balance + params.row.frozen_balance
|
||||
return h('span', { style: { color: '#409eff', fontWeight: 'bold' } },
|
||||
`¥${(total / 100).toFixed(2)}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '总收入',
|
||||
key: 'total_income',
|
||||
render: (h, params) => {
|
||||
return h('span', { style: { color: '#67c23a' } },
|
||||
`¥${(params.row.total_income / 100).toFixed(2)}`)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'create_time'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.editWallet(params.row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '详情',
|
||||
type: 'info',
|
||||
click: () => {
|
||||
this.viewDetail(params.row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
type: 'warning',
|
||||
click: () => {
|
||||
this.walletOperation(params.row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '交易记录',
|
||||
type: 'success',
|
||||
click: () => {
|
||||
this.viewTransactions(params.row)
|
||||
}
|
||||
}
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key)
|
||||
return selected ? selected.value : '请选择搜索类型'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1)
|
||||
},
|
||||
methods: {
|
||||
async query(page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
|
||||
// 构建查询参数
|
||||
const params = {
|
||||
page: page,
|
||||
pageSize: this.gridOption.param.pageOption.pageSize,
|
||||
seachOption: this.gridOption.param.seachOption
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用API获取钱包列表
|
||||
const res = await wchWalletsServer.getWalletsList(params)
|
||||
if (res.code === 0) {
|
||||
this.gridOption.data = res.data.rows || []
|
||||
this.gridOption.param.pageOption.total = res.data.count || 0
|
||||
} else {
|
||||
this.$Message.error(res.message || '获取钱包列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取钱包列表失败:', error)
|
||||
this.$Message.error('获取钱包列表失败')
|
||||
}
|
||||
},
|
||||
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
minBalance: null,
|
||||
maxBalance: null
|
||||
}
|
||||
this.query(1)
|
||||
},
|
||||
|
||||
showAddModal() {
|
||||
this.walletForm = {
|
||||
user_id: '',
|
||||
balance: '',
|
||||
frozen_balance: '',
|
||||
total_income: '',
|
||||
password: '',
|
||||
remark: ''
|
||||
}
|
||||
this.walletModalTitle = '新增钱包'
|
||||
this.walletModal = true
|
||||
},
|
||||
|
||||
editWallet(row) {
|
||||
this.walletForm = { ...row }
|
||||
this.walletModalTitle = '编辑钱包'
|
||||
this.walletModal = true
|
||||
},
|
||||
|
||||
saveWallet() {
|
||||
this.$refs.walletForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const params = { ...this.walletForm }
|
||||
|
||||
try {
|
||||
// 调用API保存钱包
|
||||
const apiCall = params.id ? wchWalletsServer.updateWallet(params) : wchWalletsServer.addWallet(params)
|
||||
const res = await apiCall
|
||||
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('钱包保存成功')
|
||||
this.walletModal = false
|
||||
this.query(1)
|
||||
} else {
|
||||
this.$Message.error(res.message || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存钱包失败:', error)
|
||||
this.$Message.error('保存失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async viewDetail(row) {
|
||||
try {
|
||||
// 调用API获取钱包详情
|
||||
const res = await wchWalletsServer.getWalletDetail({ id: row.id })
|
||||
if (res.code === 0) {
|
||||
this.walletDetail = res.data.wallet
|
||||
this.detailModal = true
|
||||
} else {
|
||||
this.$Message.error(res.message || '获取钱包详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取钱包详情失败:', error)
|
||||
this.$Message.error('获取钱包详情失败')
|
||||
}
|
||||
},
|
||||
|
||||
walletOperation(row) {
|
||||
this.currentWallet = row
|
||||
this.operationForm = {
|
||||
type: '',
|
||||
amount: '',
|
||||
reason: ''
|
||||
}
|
||||
this.operationModal = true
|
||||
},
|
||||
|
||||
confirmOperation() {
|
||||
this.$refs.operationForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$Message.success('钱包操作完成')
|
||||
this.operationModal = false
|
||||
this.operationForm = { type: '', amount: '', reason: '' }
|
||||
this.currentWallet = null
|
||||
this.query(1)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
viewTransactions(row) {
|
||||
this.$Message.info('跳转到交易记录页面')
|
||||
// 这里可以跳转到交易记录页面,传递钱包ID参数
|
||||
},
|
||||
|
||||
async exportWallets() {
|
||||
// 构建导出参数
|
||||
const params = {
|
||||
seachOption: this.gridOption.param.seachOption
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用API导出钱包数据
|
||||
const res = await wchWalletsServer.exportWallets(params)
|
||||
if (res.code === 0) {
|
||||
this.$Message.success('导出成功')
|
||||
// 这里可以添加下载文件的逻辑
|
||||
} else {
|
||||
this.$Message.error(res.message || '导出失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('导出钱包数据失败:', error)
|
||||
this.$Message.error('导出失败')
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.detail-item label {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.amount-text {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.amount-text.available {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.amount-text.frozen {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.amount-text.income {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.amount-text.expense {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.ml5 {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.mr5 {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
345
demo/src/views/statistics/resources.vue
Normal file
345
demo/src/views/statistics/resources.vue
Normal file
@@ -0,0 +1,345 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddModal">新增资源</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="(item, index) in seachTypes" :key="index" :value="item.key">{{ item.title }}
|
||||
</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="资源类型">
|
||||
<Select v-model="gridOption.param.seachOption.resource_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="image">图片</Option>
|
||||
<Option value="video">视频</Option>
|
||||
<Option value="audio">音频</Option>
|
||||
<Option value="document">文档</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<Select v-model="gridOption.param.seachOption.status" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="active">正常</Option>
|
||||
<Option value="inactive">禁用</Option>
|
||||
<Option value="deleted">已删除</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<Modal v-model="editWarp" :title="editTitle" @on-ok="save" @on-cancel="cancel" width="600">
|
||||
<Form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="100">
|
||||
<FormItem v-for="(item, index) in editColumns" :key="index" :label="item.title" :prop="item.key">
|
||||
<Input v-if="item.type === 'text'" v-model="formValidate[item.key]"
|
||||
:placeholder="'请输入' + item.title" />
|
||||
<Input v-else-if="item.type === 'textarea'" v-model="formValidate[item.key]" type="textarea"
|
||||
:placeholder="'请输入' + item.title" :rows="4" />
|
||||
<Input v-else-if="item.type === 'number'" v-model="formValidate[item.key]" type="number"
|
||||
:placeholder="'请输入' + item.title" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getList, add, edit, del, exportData } from '@/api/ball/resources_server'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import funTool from '@/libs/funTool'
|
||||
|
||||
export default {
|
||||
name: 'resources',
|
||||
data() {
|
||||
// 定义表单验证规则
|
||||
const rules = {
|
||||
resource_name: [{ required: true, message: '请输入资源名称', trigger: 'blur' }],
|
||||
resource_type: [{ required: true, message: '请输入资源类型', trigger: 'blur' }],
|
||||
resource_url: [{ required: true, message: '请输入资源链接', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
return {
|
||||
editWarp: false,
|
||||
editTitle: '新增',
|
||||
formValidate: {},
|
||||
ruleValidate: rules,
|
||||
seachTypes: [
|
||||
{ key: 'user_id', title: '用户ID' }
|
||||
],
|
||||
gridOption: {
|
||||
data: [],
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
resource_type: null,
|
||||
status: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id' },
|
||||
{
|
||||
title: '用户',
|
||||
key: 'user_id',
|
||||
render: (h, params) => {
|
||||
const userInfo = params.row.user_info;
|
||||
if (userInfo && userInfo.nickname) {
|
||||
return h('div', [
|
||||
h('img', {
|
||||
attrs: {
|
||||
src: userInfo.avatar_url || '/default-avatar.png',
|
||||
alt: userInfo.nickname,
|
||||
title: userInfo.nickname
|
||||
},
|
||||
style: {
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
borderRadius: '50%',
|
||||
marginRight: '8px',
|
||||
verticalAlign: 'middle'
|
||||
}
|
||||
}),
|
||||
h('span', { style: { verticalAlign: 'middle' } }, userInfo.nickname)
|
||||
]);
|
||||
}
|
||||
return h('span', `用户ID: ${params.row.user_id}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '资源类型',
|
||||
key: 'resource_type',
|
||||
render: (h, params) => {
|
||||
const typeMap = {
|
||||
'image': { text: '图片', color: 'blue' },
|
||||
'video': { text: '视频', color: 'purple' },
|
||||
'audio': { text: '音频', color: 'orange' },
|
||||
'document': { text: '文档', color: 'green' },
|
||||
'other': { text: '其他', color: 'default' }
|
||||
};
|
||||
const type = typeMap[params.row.resource_type] || { text: params.row.resource_type || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: type.color } }, type.text);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '文件预览',
|
||||
key: 'file_url',
|
||||
render: (h, params) => {
|
||||
const fileUrl = params.row.file_url;
|
||||
const resourceType = params.row.resource_type;
|
||||
|
||||
if (!fileUrl) {
|
||||
return h('span', { style: { color: '#c5c8ce' } }, '无文件');
|
||||
}
|
||||
|
||||
// 图片预览
|
||||
if (resourceType === 'image') {
|
||||
return h('img', {
|
||||
attrs: {
|
||||
src: fileUrl,
|
||||
alt: params.row.original_name || '图片',
|
||||
title: '点击查看大图'
|
||||
},
|
||||
style: {
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
objectFit: 'cover',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
},
|
||||
on: {
|
||||
click: () => {
|
||||
window.open(fileUrl, '_blank');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 其他文件类型显示链接
|
||||
return h('a', {
|
||||
attrs: {
|
||||
href: fileUrl,
|
||||
target: '_blank',
|
||||
title: '点击下载/查看文件'
|
||||
},
|
||||
style: {
|
||||
color: '#2d8cf0',
|
||||
textDecoration: 'none'
|
||||
}
|
||||
}, '查看文件');
|
||||
}
|
||||
},
|
||||
{ title: '文件大小(字节)', key: 'file_size' },
|
||||
{ title: 'MIME类型', key: 'mime_type' },
|
||||
{
|
||||
title: '是否公开',
|
||||
key: 'is_public',
|
||||
render: (h, params) => {
|
||||
return h('Tag', {
|
||||
props: { color: params.row.is_public == 1 ? 'green' : 'default' }
|
||||
}, params.row.is_public == 1 ? '是' : '否');
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render: (h, params) => {
|
||||
const statusMap = {
|
||||
'active': { text: '正常', color: 'green' },
|
||||
'deleted': { text: '已删除', color: 'red' },
|
||||
'pending': { text: '待审核', color: 'orange' }
|
||||
};
|
||||
const status = statusMap[params.row.status] || { text: params.row.status || '未知', color: 'default' };
|
||||
return h('Tag', { props: { color: status.color } }, status.text);
|
||||
}
|
||||
},
|
||||
{ title: '创建时间', key: 'create_time' },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.del(params.row)
|
||||
}
|
||||
}
|
||||
];
|
||||
return uiTool.getBtn(h, btns);
|
||||
}
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '资源名称', key: 'resource_name', type: 'text', required: true },
|
||||
{ title: '资源类型', key: 'resource_type', type: 'text', required: true },
|
||||
{ title: '资源链接', key: 'resource_url', type: 'text', required: true },
|
||||
{ title: '资源描述', key: 'resource_description', type: 'textarea', required: false }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1)
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page
|
||||
getList(this.gridOption.param).then(res => {
|
||||
if (res && res.data) {
|
||||
this.gridOption.data = res.data.rows || res.data
|
||||
this.gridOption.param.pageOption.total = res.data.count || 0
|
||||
}
|
||||
})
|
||||
},
|
||||
showAddModal() {
|
||||
this.editTitle = '新增'
|
||||
this.formValidate = {}
|
||||
this.editWarp = true
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.editTitle = '编辑'
|
||||
this.formValidate = { ...row }
|
||||
this.editWarp = true
|
||||
},
|
||||
save() {
|
||||
this.$refs.formValidate.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.formValidate.id) {
|
||||
edit(this.formValidate).then(res => {
|
||||
this.$Message.success('编辑成功')
|
||||
this.editWarp = false
|
||||
this.query(1)
|
||||
})
|
||||
} else {
|
||||
add(this.formValidate).then(res => {
|
||||
this.$Message.success('新增成功')
|
||||
this.editWarp = false
|
||||
this.query(1)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
this.editWarp = false
|
||||
},
|
||||
del(row) {
|
||||
this.$Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这条记录吗?',
|
||||
onOk: () => {
|
||||
del({ id: row.id }).then(res => {
|
||||
this.$Message.success('删除成功')
|
||||
this.query(1)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
exportCsv() {
|
||||
exportData(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '资源管理.csv')
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'user_id',
|
||||
value: '',
|
||||
resource_type: null,
|
||||
status: null
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.title : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.content-view {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.table-head-tool {
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.table-body {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
146
demo/src/views/users/recommend_blocks.vue
Normal file
146
demo/src/views/users/recommend_blocks.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import recommend_blocksServer from '@/api/users/recommend_blocks_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["user_id"] = [{ required: true, type: "number", message: '请填写用户ID', trigger: 'change' }];
|
||||
rules["blocked_user_id"] = [{ required: true, type: "number", message: '请填写被屏蔽用户ID', trigger: 'change' }];
|
||||
rules["block_time"] = [{ required: false, message: '请填写屏蔽时间', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'blocked_user_id', value: '被屏蔽用户ID' },
|
||||
{ key: 'nickname', value: '用户昵称' }
|
||||
],
|
||||
seachTypePlaceholder: '请选择搜索类型',
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'nickname',
|
||||
value: ''
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '用户ID', key: 'user_id', minWidth: 100 },
|
||||
{ title: '被屏蔽用户ID', key: 'blocked_user_id', minWidth: 120 },
|
||||
{ title: '用户昵称', key: 'nickname', minWidth: 150 },
|
||||
{ title: '被屏蔽用户昵称', key: 'blocked_nickname', minWidth: 150 },
|
||||
{ title: '屏蔽时间', key: 'block_time', minWidth: 160 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 160 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '用户ID', key: 'user_id', type: 'number', required: true },
|
||||
{ title: '被屏蔽用户ID', key: 'blocked_user_id', type: 'number', required: true },
|
||||
{ title: '屏蔽时间', key: 'block_time', type: 'datetime' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
recommend_blocksServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await recommend_blocksServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
exportCsv() {
|
||||
recommend_blocksServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '推荐屏蔽.csv');
|
||||
});
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'nickname',
|
||||
value: ''
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
147
demo/src/views/users/user_follows.vue
Normal file
147
demo/src/views/users/user_follows.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import menuServer from '@/api/system_high/menuServer.js'
|
||||
import user_followsServer from '@/api/users/user_follows_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["follower_id"] = [{ required: true, type: "number", message: '请填写关注者ID', trigger: 'change' }];
|
||||
rules["following_id"] = [{ required: true, type: "number", message: '请填写被关注者ID', trigger: 'change' }];
|
||||
rules["follow_time"] = [{ required: false, message: '请填写关注时间', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: 'follower_id', value: '关注者ID' },
|
||||
{ key: 'following_id', value: '被关注者ID' },
|
||||
{ key: 'nickname', value: '用户昵称' }
|
||||
],
|
||||
seachTypePlaceholder: '请选择搜索类型',
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'nickname',
|
||||
value: ''
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '关注者ID', key: 'follower_id', minWidth: 100 },
|
||||
{ title: '被关注者ID', key: 'following_id', minWidth: 120 },
|
||||
{ title: '关注者昵称', key: 'nickname', minWidth: 150 },
|
||||
{ title: '被关注者昵称', key: 'followed_nickname', minWidth: 150 },
|
||||
{ title: '关注时间', key: 'follow_time', minWidth: 160 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 160 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '关注者ID', key: 'follower_id', type: 'number', required: true },
|
||||
{ title: '被关注者ID', key: 'following_id', type: 'number', required: true },
|
||||
{ title: '关注时间', key: 'follow_time', type: 'datetime' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
user_followsServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await user_followsServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
exportCsv() {
|
||||
user_followsServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '用户关注关系.csv');
|
||||
});
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'nickname',
|
||||
value: ''
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
173
demo/src/views/users/user_tracking.vue
Normal file
173
demo/src/views/users/user_tracking.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
:placeholder="seachTypePlaceholder">
|
||||
<Option v-for="item in seachTypes" :value="item.key" :key="item.key">{{ item.value }}</Option>
|
||||
</Select>
|
||||
<Input class="ml10" v-model="gridOption.param.seachOption.value" style="width: 200px" search
|
||||
placeholder="请输入关键字" @on-search="query(1)" />
|
||||
</FormItem>
|
||||
<FormItem label="事件类型">
|
||||
<Select v-model="gridOption.param.seachOption.event_type" style="width: 120px" clearable @on-change="query(1)">
|
||||
<Option value="page_view">页面浏览</Option>
|
||||
<Option value="click">点击</Option>
|
||||
<Option value="search">搜索</Option>
|
||||
<Option value="share">分享</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" @click="query(1)">查询</Button>
|
||||
<Button type="default" @click="resetQuery" class="ml10">重置</Button>
|
||||
<Button type="default" @click="exportCsv">导出</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<tables :columns="listColumns" :value="gridOption.data" :pageOption="gridOption.param.pageOption"
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"> </editModal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import funTool from '@/libs/funTool'
|
||||
import uiTool from '@/libs/uiTool'
|
||||
import user_trackingServer from '@/api/users/user_tracking_server.js'
|
||||
export default {
|
||||
data() {
|
||||
let rules = {}
|
||||
|
||||
rules["user_id"] = [{ required: true, type: "number", message: '请填写用户ID', trigger: 'change' }];
|
||||
rules["event_type"] = [{ required: true, message: '请填写事件类型' }];
|
||||
rules["event_name"] = [{ required: true, message: '请填写事件名称' }];
|
||||
rules["page_path"] = [{ required: false, message: '请填写页面路径' }];
|
||||
rules["duration"] = [{ required: false, type: "number", message: '请填写停留时长', trigger: 'change' }];
|
||||
|
||||
return {
|
||||
seachTypes: [
|
||||
{ key: 'user_id', value: '用户ID' },
|
||||
{ key: 'event_name', value: '事件名称' },
|
||||
{ key: 'nickname', value: '用户昵称' }
|
||||
],
|
||||
gridOption: {
|
||||
param: {
|
||||
seachOption: {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
event_type: null
|
||||
},
|
||||
pageOption: {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
},
|
||||
data: [],
|
||||
rules: rules
|
||||
},
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '用户ID', key: 'user_id', minWidth: 100 },
|
||||
{ title: '用户昵称', key: 'nickname', minWidth: 120 },
|
||||
{ title: '事件类型', key: 'event_type', minWidth: 120 },
|
||||
{ title: '事件名称', key: 'event_name', minWidth: 150 },
|
||||
{ title: '页面路径', key: 'page_path', minWidth: 200 },
|
||||
{ title: '停留时长(秒)', key: 'duration', minWidth: 100 },
|
||||
{ title: 'IP地址', key: 'ip_address', minWidth: 130 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 160 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
click: () => {
|
||||
this.showEditWarp(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
type: 'error',
|
||||
click: () => {
|
||||
this.delConfirm(params.row)
|
||||
},
|
||||
},
|
||||
]
|
||||
return uiTool.getBtn(h, btns)
|
||||
},
|
||||
}
|
||||
],
|
||||
editColumns: [
|
||||
{ title: '用户ID', key: 'user_id', type: 'number', required: true },
|
||||
{ title: '事件类型', key: 'event_type', type: 'select', required: true, options: [
|
||||
{ value: 'user_soure', label: '用户来源' },
|
||||
{ value: 'page_view', label: '页面访问' },
|
||||
{ value: 'button_click', label: '按钮点击' },
|
||||
{ value: 'api_call', label: '接口调用' },
|
||||
{ value: 'user_action', label: '用户行为' },
|
||||
{ value: 'form_submit', label: '表单提交' },
|
||||
{ value: 'search', label: '搜索' },
|
||||
{ value: 'share', label: '分享' },
|
||||
{ value: 'error', label: '错误' }
|
||||
]},
|
||||
{ title: '事件名称', key: 'event_name', type: 'text', required: true },
|
||||
{ title: '页面路径', key: 'page_path', type: 'text' },
|
||||
{ title: '停留时长(秒)', key: 'duration', type: 'number' },
|
||||
{ title: 'IP地址', key: 'ip_address', type: 'text' },
|
||||
{ title: '用户代理', key: 'user_agent', type: 'textarea' }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.query(1);
|
||||
},
|
||||
methods: {
|
||||
query(page) {
|
||||
this.gridOption.param.pageOption.page = page;
|
||||
user_trackingServer.page(this.gridOption.param).then(res => {
|
||||
this.gridOption.data = res.data.rows;
|
||||
this.gridOption.param.pageOption.total = res.data.count;
|
||||
});
|
||||
},
|
||||
showAddWarp() {
|
||||
this.$refs.editModal.showModal();
|
||||
},
|
||||
showEditWarp(row) {
|
||||
this.$refs.editModal.showModal(row);
|
||||
},
|
||||
delConfirm(row) {
|
||||
uiTool.delConfirm(async () => {
|
||||
await user_trackingServer.del(row)
|
||||
rootVue.$Message.success('删除成功!')
|
||||
this.query(1)
|
||||
})
|
||||
},
|
||||
exportCsv() {
|
||||
user_trackingServer.exportCsv(this.gridOption.param).then(res => {
|
||||
funTool.downloadFile(res, '用户行为追踪.csv');
|
||||
});
|
||||
},
|
||||
resetQuery() {
|
||||
this.gridOption.param.seachOption = {
|
||||
key: 'nickname',
|
||||
value: '',
|
||||
event_type: null
|
||||
};
|
||||
this.query(1);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
seachTypePlaceholder() {
|
||||
const selected = this.seachTypes.find(item => item.key === this.gridOption.param.seachOption.key);
|
||||
return selected ? selected.value : '请选择搜索类型';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
54
demo/webpack.config.js
Normal file
54
demo/webpack.config.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const path = require('path')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
|
||||
module.exports = {
|
||||
entry: './src/main.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'app.js',
|
||||
clean: true
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader'
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['vue-style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)$/,
|
||||
type: 'asset/resource'
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './public/index.html',
|
||||
title: 'Admin Framework Demo'
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
'vue$': 'vue/dist/vue.esm.js'
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
hot: true,
|
||||
open: true,
|
||||
port: 8080,
|
||||
historyApiFallback: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
"main": "dist/admin-framework.js",
|
||||
"scripts": {
|
||||
"build": "webpack --mode production",
|
||||
"dev": "webpack --mode development --watch"
|
||||
"build:dev": "cross-env NODE_ENV=development webpack --mode production",
|
||||
"dev": "webpack --mode development --watch",
|
||||
"serve": "npm run build && npx http-server -p 8080 -o /demo/index.html",
|
||||
"serve:dev": "npm run build:dev && npx http-server -p 8080 -o /demo/index.html"
|
||||
},
|
||||
"keywords": [
|
||||
"admin",
|
||||
|
||||
@@ -82,6 +82,12 @@ html {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*滚动条整体样式*/
|
||||
*::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
@@ -103,46 +109,51 @@ html {
|
||||
background: #dcdee2;
|
||||
}
|
||||
|
||||
.ml(@i) when(@i <= 300) {
|
||||
.ml(@i) when(@i <=300) {
|
||||
.ml@{i} {
|
||||
margin-left: @i + 0px;
|
||||
}
|
||||
|
||||
.ml((@i + 5));
|
||||
}
|
||||
|
||||
.ml(5);
|
||||
|
||||
.mt(@i) when(@i <= 100) {
|
||||
.mt(@i) when(@i <=100) {
|
||||
.mt@{i} {
|
||||
margin-top: @i + 0px;
|
||||
}
|
||||
|
||||
.mt((@i + 5));
|
||||
}
|
||||
|
||||
.mt(5);
|
||||
|
||||
.pa(@i) when(@i <= 100) {
|
||||
.pa(@i) when(@i <=100) {
|
||||
.pa@{i} {
|
||||
padding: @i + 0px;
|
||||
}
|
||||
|
||||
.pa((@i + 5));
|
||||
}
|
||||
|
||||
.pa(5);
|
||||
|
||||
.w(@i) when(@i <= 100) {
|
||||
.w(@i) when(@i <=100) {
|
||||
.w@{i} {
|
||||
width: @i + 0%;
|
||||
}
|
||||
|
||||
.w((@i + 5));
|
||||
}
|
||||
|
||||
.w(5);
|
||||
|
||||
.h(@i) when(@i <= 100) {
|
||||
.h(@i) when(@i <=100) {
|
||||
.h@{i} {
|
||||
height: @i + 0%;
|
||||
}
|
||||
|
||||
.h((@i + 5));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,17 +4,23 @@ const webpack = require('webpack')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
|
||||
// 判断是否为开发环境
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
module.exports = {
|
||||
mode: 'production', // 明确指定生产模式
|
||||
target: 'web', // 明确指定浏览器环境
|
||||
entry: './src/index.js',
|
||||
devtool: isDev ? 'source-map' : false, // 开发环境生成 sourcemap
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'admin-framework.js',
|
||||
library: 'AdminFramework',
|
||||
libraryTarget: 'umd',
|
||||
libraryExport: 'default',
|
||||
globalObject: 'typeof self !== \'undefined\' ? self : this',
|
||||
library: {
|
||||
name: 'AdminFramework', // 挂载到 window.AdminFramework
|
||||
type: 'umd',
|
||||
export: 'default'
|
||||
},
|
||||
globalObject: 'window', // 明确使用 window 对象
|
||||
umdNamedDefine: true, // 为 UMD 模块添加名称
|
||||
clean: true // 构建前清理 dist 目录
|
||||
},
|
||||
@@ -166,7 +172,7 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimize: !isDev, // 开发环境不压缩
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
|
||||
Reference in New Issue
Block a user