This commit is contained in:
duan 2025-02-14 16:46:50 +08:00
commit cc6142b617
23 changed files with 958 additions and 342 deletions

View File

@ -1,176 +0,0 @@
<div align="center">
<img alt="vue3-element-admin" width="80" height="80" src="./src/assets/logo.png">
<h1>vue3-element-admin</h1>
<img src="https://img.shields.io/badge/Vue-3.5.13-brightgreen.svg"/>
<img src="https://img.shields.io/badge/Vite-6.0.5-green.svg"/>
<img src="https://img.shields.io/badge/Element Plus-2.9.1-blue.svg"/>
<img src="https://img.shields.io/badge/license-MIT-green.svg"/>
<a href="https://gitee.com/youlaiorg" target="_blank">
<img src="https://img.shields.io/badge/Author-有来开源组织-orange.svg"/>
</a>
<a href="https://gitee.com/youlaiorg/youlai-boot" target="_blank">
<img alt="有来技术" src="https://gitee.com/youlaiorg/vue3-element-admin/badge/star.svg"/>
</a>
<a href="https://github.com/youlaitech/vue3-element-admin" target="_blank">
<img alt="有来技术" src="https://img.shields.io/github/stars/youlaitech/vue3-element-admin.svg?style=social&label=Stars"/>
</a>
<a href="https://gitcode.com/youlai/vue3-element-admin" target="_blank">
<img alt="有来技术" src="https://gitcode.com/youlai/vue3-element-admin/star/badge.svg"/>
</a>
</div>
![](https://foruda.gitee.com/images/1708618984641188532/a7cca095_716974.png "rainbow.png")
<div align="center">
<a target="_blank" href="http://vue3.youlai.tech">👀 Live Preview</a> | <a target="_blank" href="https://juejin.cn/post/7228990409909108793">📖 Read Documentation</a> | 🌐 <a href="./README.md">中文
</div>
## Introduction
[vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) is a free and open-source admin template for backend management frontend, built with popular technologies such as Vue3, Vite5, TypeScript, Element-Plus, and Pinia (with accompanying [backend source code](https://gitee.com/youlaiorg/youlai-boot)).
## Project Features
- **Simple and Easy-to-use**: Upgraded version of [vue-element-admin](https://gitee.com/panjiachen/vue-element-admin) for Vue3, with minimal encapsulation and easy to get started.
- **Data Interaction**: Support both local `Mock` data and remote API. Comes with [Java backend source code](https://gitee.com/youlaiorg/youlai-boot) and online API documentation.
- **Permission Management**: Complete permission system for users, roles, menus, dictionaries, and departments.
- **Essential Infrastructure**: Dynamic routing, button permissions, internationalization, code style, Git commit conventions, and common component encapsulation.
- **Continuous Updates**: Since 2021, the project has maintained an open-source status with continuous updates, integrating new tools and dependencies in real time, and has accumulated a broad user base.
## Project Preview
![Light Mode](https://foruda.gitee.com/images/1709651876583793739/0ba1ee1c_716974.png)
![Dark Mode](https://foruda.gitee.com/images/1709651875494206224/2a2b0b53_716974.png)
![API Documentation](https://foruda.gitee.com/images/1687755822857820115/96054330_716974.png)
## Project Links
| Project | Gitee | Github | GitCode |
|----------| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| Frontend | [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) | [vue3-element-admin](https://github.com/youlaitech/vue3-element-admin) | [vue3-element-admin](https://gitcode.net/youlai/vue3-element-admin) |
| Lite | [vue3-element-template](https://gitee.com/youlaiorg/vue3-element-template) | [vue3-element-template](https://github.com/youlaitech/vue3-element-template) |-|
| Backend | [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) | [youlai-boot](https://github.com/haoxianrui/youlai-boot.git) | [youlai-boot](https://gitcode.net/youlai/youlai-boot) |
## Environment Setup
| Environment | Name and Version | Download Link |
| -------------------- | :----------------------------------------------------------- | ------------------------------------------------------------ |
| **Development Tool** | VSCode | [Download](https://code.visualstudio.com/Download) |
| **Runtime Environment** | Node ≥18 | [Download](http://nodejs.cn/download) |
## Project Setup
```bash
# Clone the repository
git clone https://gitee.com/youlaiorg/vue3-element-admin.git
# Change directory
cd vue3-element-admin
# Install pnpm
npm install pnpm -g
# Install dependencies
pnpm install
# Start the project
pnpm run dev
```
## Project Deployment
```bash
# Build the project
pnpm run build
# Upload files to the remote server
Copy the files generated in the `dist` directory to the `/usr/share/nginx/html` directory.
# nginx.cofig configuration
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# Reverse proxy configuration
location /prod-api/ {
proxy_pass http://vapi.youlai.tech/; # Replace vapi.youlai.tech with your backend API address
}
}
```
## Local Mock
The project supports both online API and local mock API. By default, it uses the online API. If you want to switch to the mock API, modify the value of `VITE_MOCK_DEV_SERVER` in the `.env.development` file to `true`.
## Backend API
> If you have a basic understanding of Java development, follow these steps to convert online API to local backend API and set up a full-stack development environment.
1. Get the backend source code based on `Java` and `SpringBoot` from [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git).
2. Follow the instructions in the backend project's README.md to set up the local environment.
3. Modify the value of `VITE_APP_API_URL` in the `.env.development` file to `http://localhost:8989`, replacing it with the backend API URL.
## Notes
- **Auto import plugin is disabled by default**
Component type declarations have been automatically generated for the template project. If you add and use new components, follow the instructions in the screenshot to enable automatic generation. After automatic generation is complete, remember to set it back to `false` to avoid conflicts.
![](https://foruda.gitee.com/images/1687755823137387608/412ea803_716974.png)
- **Blank page when accessing the project**
Try upgrading your browser, as older browser engines may not support certain new JavaScript syntax, such as optional chaining operator `?.`.
- **Red highlight on project components, functions, and imports**
Restart VSCode to try again.
- **Other issues**
If you have any other issues or suggestions, please open an [issue](https://gitee.com/youlaiorg/vue3-element-admin/issues/new).
## Project Documentation
- [Building a Backend Management System from Scratch with Vue3, Vite, TypeScript, and Element-Plus](https://blog.csdn.net/u013737132/article/details/130191394)
- [ESLint+Prettier+Stylelint+EditorConfig for Standardized and Unified Frontend Code Style](https://blog.csdn.net/u013737132/article/details/130190788)
- [Git Commit Conventions with Husky, Lint-staged, Commitlint, Commitizen, and cz-git](https://blog.csdn.net/u013737132/article/details/130191363)
## Commit Conventions
Execute `pnpm run commit` to invoke interactive git commit and complete the information input and selection according to the prompts.
![](https://foruda.gitee.com/images/1687755823165218215/c1705416_716974.png)
## Community 🚀
> **Follow "Youlai Tech" WeChat Official Account to get the QR code for the community.**
>
> If the QR code for the community has expired, please add my WeChat (haoxianrui) and indicate whether you are interested in "Frontend", "Backend", or "Full Stack" to get the latest QR code.
>
> This measure is taken to ensure the quality of the community and prevent marketing advertising from infiltrating. Thank you for your understanding!
| Official Account | Community |
|:----:|:----:|
| ![Youlai Tech WeChat Official Account QR Code](https://foruda.gitee.com/images/1687689212187063809/3c69eaee_716974.png) | ![Community QR Code](https://foruda.gitee.com/images/1687689212139273561/6a65ef69_716974.png) |

216
src/api/system/order.ts Normal file
View File

@ -0,0 +1,216 @@
import request from "@/utils/request";
import { System_BaseUrl } from "@/api/config";
const baseURL = System_BaseUrl + "/admin/order";
const OrderApi = {
getList(params: getListRequest) {
return request<any, getListResponse>({
url: `${baseURL}`,
method: "get",
params: params,
});
},
add() {},
edit() {},
delete() {},
};
export default OrderApi;
// 订单状态
export type statusType =
| "unpaid"
| "in-production"
| "wait-out"
| "done"
| "refunding"
| "refund"
| "part-refund"
| "cancelled"
| "";
// 发货类型
export type sendType = "post" | "takeaway" | "takeself" | "table" | "";
//订单类型
export type orderType = "cash" | "miniapp" | "offline" | "";
//是否回收站 0-否1回收站 默认查未删除
export type isDel = 0 | 1;
export interface getListRequest {
endTime?: string;
/**
* 0-1
*/
isDel?: isDel;
/**
*
*/
orderNo?: string;
/**
* -cash收银-miniapp小程序-offline线下
*/
orderType?: orderType;
/**
*
*/
payType?: string;
/**
*
*/
platformType?: string;
/**
*
*/
productName?: string;
/**
* post快递takeaway外卖,takeself,table---
*/
sendType?: sendType;
/**
* Id
*/
shopId?: number;
startTime?: string;
/**
* 状态: unpaid-;in-production ;wait-out
* ;;done-;refunding-退;refund-退;part-refund 退;cancelled-
*/
status?: statusType;
/**
* id
*/
tableId?: string;
/**
*
*/
tableName?: string;
[property: string]: any;
}
/**
* CzgResultPageOrderInfoVo
*/
export interface getListResponse {
code?: number;
data?: PageOrderInfoVo;
msg?: string;
[property: string]: any;
}
/**
* PageOrderInfoVo
*/
export interface PageOrderInfoVo {
maxPageSize?: number;
optimizeCountQuery?: boolean;
pageNumber?: number;
pageSize?: number;
records?: OrderInfoVo[];
totalPage?: number;
totalRow?: number;
[property: string]: any;
}
/**
*
*
* OrderInfoVo
*/
export interface OrderInfoVo {
createTime?: string;
/**
* dine-in take-out take-away
*/
dineMode?: string;
/**
*
*/
goods?: OrderDetailSmallVO[];
id?: number;
/**
* 使
*/
isFreeDine?: number;
/**
* ()
*/
orderAmount?: number;
/**
*
*/
orderNo?: string;
/**
* -
* cash收银( )
* miniapp小程序
*/
orderType?: orderType;
/**
*
*/
originAmount?: number;
/**
*
*/
paidTime?: string;
/**
*
*/
payAmount?: number;
/**
*
*/
payOrderNo?: string;
/**
*
* main-scan
* back-scan
* wechat-mini
* alipay-mini
* vip-pay
* cash-pay
*/
payType?: string;
/**
* pc wechat alipay admin-pc PC管理端 admin-app APP管理端
*/
platformType?: string;
/**
* 退1退 0退
*/
refundAble?: number;
/**
* 退
*/
refundAmount?: number;
/**
*
*/
remark?: string;
/**
* Id
*/
shopId?: string;
/**
* 状态: unpaid-;in-production ;wait-out
* ;;done-;refunding-退;refund-退;part-refund 退;cancelled-
*/
status?: statusType;
/**
*
*/
tableName?: string;
[property: string]: any;
}
/**
*
*
* OrderDetailSmallVO
*/
export interface OrderDetailSmallVO {
num?: number;
productImg?: string;
productName?: string;
refundNum?: number;
skuName?: string;
[property: string]: any;
}

View File

@ -4,14 +4,28 @@ const baseURL = System_BaseUrl + "/admin/version";
const VersionApi = {
getList() {
return request<any, getListResponse>({
return request<any>({
url: `${baseURL}/list`,
method: "get",
});
},
add(data: addRequest) {
return request<any>({
url: `${baseURL}`,
method: "post",
data,
});
},
edit(data: editRequest) {
return request<any>({
url: `${baseURL}`,
method: "put",
data,
});
},
delete(id: string) {
return request<any>({
url: `${baseURL}/id`,
url: `${baseURL}/` + id,
method: "delete",
});
},
@ -19,7 +33,7 @@ const VersionApi = {
export default VersionApi;
export interface getListResponse {
export interface versionForm {
/**
* id
*/
@ -50,3 +64,62 @@ export interface getListResponse {
version?: string;
[property: string]: any;
}
export interface addRequest {
/**
* 01
*/
isForce: number;
/**
*
*/
message: string;
/**
* pc manager_app phone_book
*/
source: string;
/**
* 0 windows1 2 iOS
*/
type: string;
/**
*
*/
url: string;
/**
*
*/
version: string;
[property: string]: any;
}
export interface editRequest {
/**
* idID
*/
id: number;
/**
* 01
*/
isForce: number;
/**
*
*/
message: string;
/**
* pc manager_app phone_book
*/
source: string;
/**
* 0 windows1 2 iOS
*/
type: string;
/**
*
*/
url: string;
/**
*
*/
version: string;
[property: string]: any;
}

View File

@ -28,7 +28,7 @@
</template>
<!-- textarea 输入框 -->
<template v-else-if="item.type === 'textarea' || item.type === undefined">
<template v-else-if="item.type === 'textarea'">
<el-input v-model="formData[item.prop]" type="textarea" v-bind="item.attrs" />
</template>
<!-- Select 选择器 -->

View File

@ -24,8 +24,8 @@
<el-input v-model="formData[item.prop]" v-bind="item.attrs" />
</template>
<!-- textarea 输入框 -->
<template v-if="item.type === 'textarea' || item.type === undefined">
<el-input v-model="formData[item.prop]" v-bind="item.attrs" />
<template v-if="item.type === 'textarea'">
<el-input v-model="formData[item.prop]" v-bind="item.attrs" type="textarea" />
</template>
<!-- Select 选择器 -->
<template v-else-if="item.type === 'select'">
@ -123,6 +123,10 @@
<template v-if="item.type === 'input' || item.type === undefined">
<el-input v-model="formData[item.prop]" v-bind="item.attrs" />
</template>
<!-- textarea 输入框 -->
<template v-if="item.type === 'textarea'">
<el-input v-model="formData[item.prop]" v-bind="item.attrs" type="textarea" />
</template>
<!-- Select 选择器 -->
<template v-else-if="item.type === 'select'">
<el-select v-model="formData[item.prop]" v-bind="item.attrs">

View File

@ -5,7 +5,7 @@
shadow="never"
class="mb-[10px]"
>
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form ref="queryFormRef" :model="queryParams" :inline="inline">
<template v-for="(item, index) in formItems" :key="item.prop">
<el-form-item
v-show="isExpand ? true : index < showNumber"
@ -36,6 +36,14 @@
@keyup.enter="handleQuery"
/>
</template>
<!-- radio-button radio按钮组 -->
<template v-if="item.type === 'radio-button'">
<el-radio-group v-model="queryParams[item.prop]" v-bind="item.attrs">
<template v-for="option in item.options" :key="option.value">
<el-radio-button :label="option.label" :value="option.value" />
</template>
</el-radio-group>
</template>
<!-- InputTag 标签输入框 -->
<template v-if="item.type === 'input-tag'">
<div class="flex-center">
@ -131,6 +139,10 @@ const emit = defineEmits<{
}>();
const queryFormRef = ref<FormInstance>();
//form
const inline = ref<boolean>(
props.searchConfig.inline === undefined ? true : !!props.searchConfig.inline
);
//
const visible = ref(true);
// formItems

View File

@ -29,10 +29,11 @@ export interface IOperatData {
export interface ISearchConfig {
// 页面名称(参与组成权限标识,如sys:user:xxx)
pageName: string;
inline?: Boolean;
// 表单项
formItems: Array<{
// 组件类型(如input,select等)
type?: "input" | "select" | "tree-select" | "date-picker" | "input-tag";
type?: "input" | "select" | "tree-select" | "date-picker" | "input-tag" | "radio-button";
// 标签文本
label: string;
// 标签提示

View File

@ -49,7 +49,7 @@ import {
UploadRequestOptions,
} from "element-plus";
import FileAPI, { FileInfo } from "@/api/file";
import CommonApi, { FileInfo, uploadResponse } from "@/api/account/common";
const props = defineProps({
/**
@ -165,7 +165,7 @@ function handleUpload(options: UploadRequestOptions) {
formData.append(key, props.data[key]);
});
FileAPI.upload(formData)
CommonApi.upload(formData)
.then((data) => {
resolve(data);
})
@ -187,9 +187,9 @@ const handleProgress = (event: UploadProgressEvent) => {
/**
* 上传成功
*/
const handleSuccess = (fileInfo: FileInfo) => {
const handleSuccess = (fileInfo: string) => {
ElMessage.success("上传成功");
modelValue.value = [...modelValue.value, fileInfo.url];
modelValue.value = [...modelValue.value, fileInfo];
};
const handleError = (error: any) => {
@ -200,19 +200,19 @@ const handleError = (error: any) => {
* 删除文件
*/
function handleRemove(fileUrl: string) {
FileAPI.delete(fileUrl).then(() => {
modelValue.value = modelValue.value.filter((url) => url !== fileUrl);
});
// CommonApi.delete(fileUrl).then(() => {
modelValue.value = modelValue.value.filter((url) => url !== fileUrl);
// });
}
/**
* 下载文件
*/
function handleDownload(file: UploadUserFile) {
const { url, name } = file;
if (url) {
FileAPI.download(url, name);
}
// const { url, name } = file;
// if (url) {
// CommonApi.download(url, name);
// }
}
</script>
<style lang="scss" scoped>

View File

@ -40,7 +40,7 @@ const isSidebarCollapsed = computed(() => !appStore.sidebar.opened);
<style lang="scss" scoped>
.has-logo {
.el-scrollbar {
height: calc(100vh - $navbar-height);
height: calc(100vh - $navbar-height - $window-top);
}
}
</style>

View File

@ -463,7 +463,7 @@ export const constantRoutes: RouteRecordRaw[] = [
children: [
{
path: "index",
component: () => import("@/views/order/index.vue"),
component: () => import("@/views/order/index/index.vue"),
name: "orderIndex",
meta: {
title: "订单列表",

View File

@ -12,8 +12,8 @@ declare global {
*
*/
interface PageQuery {
pageNum: number;
pageSize: number;
page: number;
size: number;
}
/**

View File

@ -1,7 +1,8 @@
import UserAPI, { type UserForm } from "@/api/system/user";
import VersionApi, { type addRequest } from "@/api/system/version";
import { sourceOptions, typeOptions, isForceOptions } from "./config";
import type { IModalConfig } from "@/components/CURD/types";
const modalConfig: IModalConfig<UserForm> = {
const modalConfig: IModalConfig<addRequest> = {
pageName: "sys:user",
dialog: {
title: "新增版本",
@ -11,7 +12,9 @@ const modalConfig: IModalConfig<UserForm> = {
form: {
labelWidth: 140,
},
formAction: UserAPI.add,
formAction: function (data) {
return VersionApi.add({ ...data, url: typeof data.url === "string" ? data.url : data.url[0] });
},
beforeSubmit(data) {
console.log("提交之前处理", data);
},
@ -24,11 +27,7 @@ const modalConfig: IModalConfig<UserForm> = {
attrs: {
placeholder: "请选择渠道",
},
options: [
{ label: "桌面端", value: "pc" },
{ label: "管理端", value: "manager_app" },
{ label: "电话机点餐", value: "phone_book " },
],
options: sourceOptions,
},
{
label: "类型",
@ -42,11 +41,7 @@ const modalConfig: IModalConfig<UserForm> = {
xs: 24,
sm: 12,
},
options: [
{ label: "windows", value: 0 },
{ label: "安卓", value: 1 },
{ label: "iOS", value: 2 },
],
options: typeOptions,
},
{
type: "input",
@ -66,20 +61,27 @@ const modalConfig: IModalConfig<UserForm> = {
placeholder: "请输入版本号",
},
initialValue: 0,
options: [
{ label: "是", value: 1 },
{ label: "否", value: 0 },
],
options: isForceOptions,
},
{
type: "textarea",
label: "更新提示内容",
prop: "version",
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
prop: "message",
rules: [{ required: true, message: "请输入更新提示内容", trigger: "blur" }],
attrs: {
placeholder: "请输入版本号",
placeholder: "请输入更新提示内容",
},
},
{
type: "custom",
label: "版本文件",
prop: "url",
rules: [{ required: true, message: "请上传版本文件", trigger: "blur" }],
attrs: {
placeholder: "请上传版本文件",
},
initialValue: [],
},
],
};

View File

@ -0,0 +1,45 @@
import { property } from "lodash";
export const sourceOptions: options[] = [
{ label: "桌面端", value: "pc" },
{ label: "管理端", value: "manager_app" },
{ label: "电话机点餐", value: "phone_book " },
];
export const typeOptions: options[] = [
{ label: "windows", value: "0" },
{ label: "安卓", value: "1" },
{ label: "IOS", value: "2" },
];
export const isForceOptions: options[] = [
{ label: "不强制更新", value: 0 },
{ label: "强制更新", value: 1 },
];
export type optionsType = "source" | "type" | "isForce";
export function returnOptions(type: optionsType) {
if (type === "source") {
return sourceOptions;
}
if (type === "type") {
return typeOptions;
}
if (type === "isForce") {
return isForceOptions;
}
}
export function returnOptionsLabel(optionsType: optionsType, value: string | number) {
const options = returnOptions(optionsType);
if (!options) {
return "";
}
const option = options.find((item) => item.value === value);
return option ? option.label : "";
}
export interface options {
label: string;
value: string | number;
[property: string]: any;
}

View File

@ -1,9 +1,8 @@
import VersionApi from "@/api/system/version";
import RoleAPI from "@/api/system/role";
import type { UserPageQuery } from "@/api/system/user";
import type { editRequest } from "@/api/system/version";
import type { IContentConfig } from "@/components/CURD/types";
const contentConfig: IContentConfig<UserPageQuery> = {
const contentConfig: IContentConfig<editRequest> = {
pageName: "sys:user",
table: {
border: true,
@ -19,30 +18,37 @@ const contentConfig: IContentConfig<UserPageQuery> = {
return VersionApi.getList();
},
deleteAction: VersionApi.delete,
importsAction(data) {
// 模拟导入数据
console.log("importsAction", data);
return Promise.resolve();
},
exportsAction: async function (params) {
// 模拟获取到的是全量数据
const res = await VersionApi.getList(params);
console.log("exportsAction", res.list);
return res.list;
},
// modifyAction: function (data) {
// // return VersionApi.edit(data);
// },
pk: "id",
toolbar: ["add"],
defaultToolbar: ["refresh", "filter", "search"],
cols: [
{ type: "selection", width: 50, align: "center" },
{ label: "id", align: "center", prop: "id", width: 100, show: true },
{ label: "渠道", align: "center", prop: "source" },
{
label: "渠道",
align: "center",
prop: "source",
width: 120,
templet: "custom",
slotName: "options",
},
{
label: "类型",
align: "center",
prop: "type",
width: 120,
templet: "custom",
slotName: "options",
},
{
label: "版本号",
align: "center",
width: 120,
prop: "version",
},
{ label: "版本号", align: "center", prop: "version" },
{
label: "是否强制升级",
@ -52,6 +58,12 @@ const contentConfig: IContentConfig<UserPageQuery> = {
templet: "switch",
slotName: "isForce",
},
{
label: "更新内容",
align: "center",
prop: "message",
width: 240,
},
{
label: "下载地址",
align: "center",
@ -65,20 +77,7 @@ const contentConfig: IContentConfig<UserPageQuery> = {
fixed: "right",
width: 280,
templet: "tool",
operat: [
{
icon: "Document",
name: "edit",
text: "编辑",
},
{
name: "delete",
icon: "delete",
text: "删除",
},
"edit",
"delete",
],
operat: ["edit", "delete"],
},
],
};

View File

@ -1,116 +1,85 @@
import UserAPI, { type UserForm } from "@/api/system/user";
import VersionApi, { type editRequest } from "@/api/system/version";
import type { IModalConfig } from "@/components/CURD/types";
import { DeviceEnum } from "@/enums/DeviceEnum";
import { useAppStore } from "@/store";
import { sourceOptions, typeOptions, isForceOptions } from "./config";
const modalConfig: IModalConfig<UserForm> = {
const modalConfig: IModalConfig<editRequest> = {
pageName: "sys:user",
component: "drawer",
drawer: {
title: "修改用户",
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
dialog: {
title: "编辑版本",
width: 800,
draggable: true,
},
pk: "id",
formAction: function (data) {
return UserAPI.update(data.id as number, data);
return VersionApi.edit({ ...data, url: typeof data.url === "string" ? data.url : data.url[0] });
},
beforeSubmit(data) {
console.log("提交之前处理", data);
},
formItems: [
{
label: "用户名",
prop: "username",
rules: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
type: "input",
label: "渠道",
prop: "source",
rules: [{ required: true, message: "请选择渠道", trigger: "blur" }],
type: "select",
attrs: {
placeholder: "请输入用户名",
readonly: true,
placeholder: "请选择渠道",
},
options: sourceOptions,
},
{
label: "类型",
prop: "type",
rules: [{ required: true, message: "请选择类型", trigger: "blur" }],
type: "select",
attrs: {
placeholder: "请选择类型",
},
col: {
xs: 24,
sm: 12,
},
options: typeOptions,
},
{
type: "input",
label: "版本号",
prop: "version",
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
attrs: {
placeholder: "请输入版本号",
},
},
{
label: "用户昵称",
prop: "nickname",
rules: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
type: "input",
type: "radio",
label: "是否强制更新",
prop: "isForce",
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
attrs: {
placeholder: "请输入用户昵称",
placeholder: "请输入版本号",
},
initialValue: 0,
options: isForceOptions,
},
{
label: "所属部门",
prop: "deptId",
rules: [{ required: true, message: "所属部门不能为空", trigger: "blur" }],
type: "tree-select",
type: "textarea",
label: "更新提示内容",
prop: "message",
rules: [{ required: true, message: "请输入更新提示内容", trigger: "blur" }],
attrs: {
placeholder: "请选择所属部门",
data: [],
filterable: true,
"check-strictly": true,
"render-after-expand": false,
placeholder: "请输入更新提示内容",
},
},
{
type: "custom",
label: "性别",
prop: "gender",
initialValue: 1,
},
{
label: "角色",
prop: "roleIds",
rules: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
type: "select",
label: "版本文件",
prop: "url",
rules: [{ required: true, message: "请上传版本文件", trigger: "blur" }],
attrs: {
placeholder: "请选择",
multiple: true,
placeholder: "请上传版本文件",
},
options: [],
initialValue: [],
},
{
type: "input",
label: "手机号码",
prop: "mobile",
rules: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur",
},
],
attrs: {
placeholder: "请输入手机号码",
maxlength: 11,
},
},
{
label: "邮箱",
prop: "email",
rules: [
{
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
message: "请输入正确的邮箱地址",
trigger: "blur",
},
],
type: "input",
attrs: {
placeholder: "请输入邮箱",
maxlength: 50,
},
},
{
label: "状态",
prop: "status",
type: "switch",
attrs: {
activeText: "正常",
inactiveText: "禁用",
activeValue: 1,
inactiveValue: 0,
},
},
],
};

View File

@ -26,6 +26,9 @@
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
</el-tag>
</template>
<template #options="scope">
{{ returnOptionsLabel(scope.prop, scope.row[scope.prop]) }}
</template>
<template #gender="scope">
<DictLabel v-model="scope.row[scope.prop]" code="gender" />
</template>
@ -45,8 +48,9 @@
:modal-config="addModalConfig"
@submit-click="handleSubmitClick"
>
<template #gender="scope">
<Dict v-model="scope.formData[scope.prop]" code="gender" />
<template #url="scope">
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
<!-- <Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" /> -->
</template>
</page-modal>
@ -56,8 +60,9 @@
:modal-config="editModalConfig"
@submit-click="handleSubmitClick"
>
<template #gender="scope">
<Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" />
<template #url="scope">
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
<!-- <Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" /> -->
</template>
</page-modal>
</template>
@ -88,6 +93,7 @@ import contentConfig from "./config/content";
import contentConfig2 from "./config/content2";
import editModalConfig from "./config/edit";
import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config";
const {
searchRef,
@ -108,18 +114,20 @@ const {
async function handleAddClick() {
addModalRef.value?.setModalVisible();
//
addModalConfig.formItems[2]!.attrs!.data = await DeptAPI.getOptions();
// addModalConfig.formItems[2]!.attrs!.data = await DeptAPI.getOptions();
//
addModalConfig.formItems[4]!.options = await RoleAPI.getOptions();
// addModalConfig.formItems[4]!.options = await RoleAPI.getOptions();
}
//
async function handleEditClick(row: IObject) {
editModalRef.value?.handleDisabled(false);
editModalRef.value?.setModalVisible();
// id
const data = await VersionApi.getFormData(row.id);
editModalRef.value?.setFormData(data);
// const data = await VersionApi.getFormData(row.id);
console.log({ ...row, url: [row.url] });
editModalRef.value?.setFormData({ ...row, url: [row.url] });
}
1;
//
function handleToolbarClick(name: string) {
console.log(name);

View File

@ -1 +0,0 @@
<template></template>

View File

@ -0,0 +1,88 @@
import VersionApi, { type addRequest } from "@/api/system/version";
import type { IModalConfig } from "@/components/CURD/types";
const modalConfig: IModalConfig<addRequest> = {
pageName: "sys:user",
dialog: {
title: "新增版本",
width: 800,
draggable: true,
},
form: {
labelWidth: 140,
},
formAction: function (data) {
return VersionApi.add({ ...data, url: typeof data.url === "string" ? data.url : data.url[0] });
},
beforeSubmit(data) {
console.log("提交之前处理", data);
},
formItems: [
{
label: "渠道",
prop: "source",
rules: [{ required: true, message: "请选择渠道", trigger: "blur" }],
type: "select",
attrs: {
placeholder: "请选择渠道",
},
options: [],
},
{
label: "类型",
prop: "type",
rules: [{ required: true, message: "请选择类型", trigger: "blur" }],
type: "select",
attrs: {
placeholder: "请选择类型",
},
col: {
xs: 24,
sm: 12,
},
options: [],
},
{
type: "input",
label: "版本号",
prop: "version",
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
attrs: {
placeholder: "请输入版本号",
},
},
{
type: "radio",
label: "是否强制更新",
prop: "isForce",
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
attrs: {
placeholder: "请输入版本号",
},
initialValue: 0,
options: [],
},
{
type: "textarea",
label: "更新提示内容",
prop: "message",
rules: [{ required: true, message: "请输入更新提示内容", trigger: "blur" }],
attrs: {
placeholder: "请输入更新提示内容",
},
},
{
type: "custom",
label: "版本文件",
prop: "url",
rules: [{ required: true, message: "请上传版本文件", trigger: "blur" }],
attrs: {
placeholder: "请上传版本文件",
},
initialValue: [],
},
],
};
// 如果有异步数据会修改配置的推荐用reactive包裹而纯静态配置的可以直接导出
export default reactive(modalConfig);

View File

@ -0,0 +1,79 @@
import type { statusType } from "@/api/system/order";
export const statusOptions: statusOptions[] = [
{ label: "全部", value: "" },
{ label: "待支付", value: "unpaid" },
{ label: "制作中", value: "in-production" },
{ label: "待取餐", value: "wait-out" },
{ label: "订单完成", value: "done" },
{ label: "申请退单", value: "refunding" },
{ label: "退单", value: "refund" },
{ label: "部分退单", value: "part-refund" },
{ label: "取消订单", value: "cancelled" },
];
export const payTypeOptions: payTypeOptions[] = [
{ label: "全部", value: "" },
{
label: "现金",
value: "cash",
},
{
label: "银行卡",
value: "bank",
},
{
label: "扫码支付",
value: "scanCode",
},
{
label: "储值卡",
value: "deposit",
},
{
label: "会员支付",
value: "vipPay",
},
{
label: "挂账",
value: "arrears",
},
];
export type optionsType = "status";
export function returnOptions(type: optionsType) {
if (type === "status") {
return statusOptions;
}
}
export function returnOptionsLabel(optionsType: optionsType, value: string | number) {
const options = returnOptions(optionsType);
if (!options) {
return "";
}
const option = options.find((item) => item.value === value);
return option ? option.label : "";
}
export interface options {
label: string;
value: string | number;
[property: string]: any;
}
export interface statusOptions extends options {
value: statusType;
}
export type payTypeValue =
| ""
| "cash"
| "bank"
| "scanCode"
| "deposit"
| "vipPay"
| "arrears"
| "virtual"
| "arrears";
export interface payTypeOptions extends options {
value: payTypeValue;
}

View File

@ -0,0 +1,59 @@
import OrderApi from "@/api/system/order";
import type { editRequest } from "@/api/system/version";
import type { IContentConfig } from "@/components/CURD/types";
const contentConfig: IContentConfig = {
pageName: "sys:user",
table: {
border: true,
highlightCurrentRow: true,
},
pagination: {
background: true,
layout: "prev,pager,next,jumper,total,sizes",
pageSize: 20,
pageSizes: [10, 20, 30, 50],
},
indexAction: function (params) {
return OrderApi.getList(params);
},
// deleteAction: OrderApi.delete,
// modifyAction: function (data) {
// // return OrderApi.edit(data);
// },
pk: "id",
toolbar: ["add"],
defaultToolbar: ["refresh", "filter", "search"],
cols: [
{ type: "selection", width: 50, align: "center" },
// { label: "id", align: "center", prop: "id", width: 100, show: true },
{
label: "订单号信息",
align: "center",
prop: "orderNo",
width: 120,
},
{
label: "操作",
align: "center",
fixed: "right",
width: 280,
templet: "tool",
operat: [
{
icon: "Document",
name: "detail",
text: "详情",
},
{
icon: "Printer",
name: "printer",
text: "开票",
},
],
},
],
};
export default contentConfig;

View File

@ -0,0 +1,51 @@
import VersionApi, { type editRequest } from "@/api/system/version";
import type { IModalConfig } from "@/components/CURD/types";
const modalConfig: IModalConfig<editRequest> = {
pageName: "sys:user",
dialog: {
title: "编辑版本",
width: 800,
draggable: true,
},
pk: "id",
formAction: function (data) {
return VersionApi.edit({ ...data, url: typeof data.url === "string" ? data.url : data.url[0] });
},
beforeSubmit(data) {
console.log("提交之前处理", data);
},
formItems: [
{
type: "input",
label: "版本号",
prop: "version",
rules: [{ required: true, message: "请输入版本号", trigger: "blur" }],
attrs: {
placeholder: "请输入版本号",
},
},
{
type: "textarea",
label: "更新提示内容",
prop: "message",
rules: [{ required: true, message: "请输入更新提示内容", trigger: "blur" }],
attrs: {
placeholder: "请输入更新提示内容",
},
},
{
type: "custom",
label: "版本文件",
prop: "url",
rules: [{ required: true, message: "请上传版本文件", trigger: "blur" }],
attrs: {
placeholder: "请上传版本文件",
},
initialValue: [],
},
],
};
export default reactive(modalConfig);

View File

@ -0,0 +1,57 @@
import type { ISearchConfig } from "@/components/CURD/types";
import { statusOptions, payTypeOptions } from "./config";
const searchConfig: ISearchConfig = {
pageName: "sys:user",
inline: false,
isExpandable: false,
formItems: [
{
type: "radio-button",
label: "订单状态",
prop: "status",
attrs: {
placeholder: "请选择订单状态",
clearable: true,
},
options: statusOptions,
initialValue: "",
},
{
type: "radio-button",
label: "支付方式",
prop: "payType",
attrs: {
placeholder: "请选择支付方式",
clearable: true,
},
options: payTypeOptions,
initialValue: "",
},
{
type: "input",
label: "订单编号",
prop: "orderNo",
attrs: {
placeholder: "请输入订单编号",
clearable: true,
style: {
width: "200px",
},
},
},
{
type: "input",
label: "商品名称",
prop: "productName",
attrs: {
placeholder: "请输入商品名称",
clearable: true,
style: {
width: "200px",
},
},
},
],
};
export default searchConfig;

View File

@ -0,0 +1,130 @@
<template>
<div class="app-container">
<!-- 列表 -->
<!-- 搜索 -->
<page-search
ref="searchRef"
:search-config="searchConfig"
@query-click="handleQueryClick"
@reset-click="handleResetClick"
/>
<!-- 列表 -->
<page-content
ref="contentRef"
:content-config="contentConfig"
@add-click="handleAddClick"
@edit-click="handleEditClick"
@export-click="handleExportClick"
@search-click="handleSearchClick"
@toolbar-click="handleToolbarClick"
@operat-click="handleOperatClick"
@filter-change="handleFilterChange"
>
<template #status="scope">
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
</el-tag>
</template>
<template #options="scope">
{{ returnOptionsLabel(scope.prop, scope.row[scope.prop]) }}
</template>
<template #gender="scope">
<DictLabel v-model="scope.row[scope.prop]" code="gender" />
</template>
<template #mobile="scope">
<el-text>{{ scope.row[scope.prop] }}</el-text>
<copy-button
v-if="scope.row[scope.prop]"
:text="scope.row[scope.prop]"
style="margin-left: 2px"
/>
</template>
</page-content>
<!-- 新增 -->
<page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick">
<template #url="scope">
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
<!-- <Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" /> -->
</template>
</page-modal>
<!-- 编辑 -->
<page-modal
ref="editModalRef"
:modal-config="editModalConfig"
@submit-click="handleSubmitClick"
>
<template #url="scope">
<FileUpload v-model="scope.formData[scope.prop]" :limit="1" v-bind="scope.attrs" />
<!-- <Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" /> -->
</template>
</page-modal>
</div>
</template>
<script setup lang="ts">
import VersionApi from "@/api/system/version";
import DeptAPI from "@/api/system/dept";
import RoleAPI from "@/api/system/role";
import type { IObject, IOperatData } from "@/components/CURD/types";
import usePage from "@/components/CURD/usePage";
import addModalConfig from "./config/add";
import contentConfig from "./config/content";
import editModalConfig from "./config/edit";
import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config";
const {
searchRef,
contentRef,
addModalRef,
editModalRef,
handleQueryClick,
handleResetClick,
// handleAddClick,
// handleEditClick,
handleSubmitClick,
handleExportClick,
handleSearchClick,
handleFilterChange,
} = usePage();
//
async function handleAddClick() {
addModalRef.value?.setModalVisible();
//
// addModalConfig.formItems[2]!.attrs!.data = await DeptAPI.getOptions();
//
// addModalConfig.formItems[4]!.options = await RoleAPI.getOptions();
}
//
async function handleEditClick(row: IObject) {
editModalRef.value?.handleDisabled(false);
editModalRef.value?.setModalVisible();
// id
// const data = await VersionApi.getFormData(row.id);
console.log({ ...row, url: [row.url] });
editModalRef.value?.setFormData({ ...row, url: [row.url] });
}
1;
//
function handleToolbarClick(name: string) {
console.log(name);
if (name === "custom1") {
ElMessage.success("点击了自定义1按钮");
}
}
//
async function handleOperatClick(data: IOperatData) {
console.log(data);
if (data.name === "detail") {
return;
}
if (data.name === "printer") {
}
}
//
const isA = ref(true);
</script>