refactor: 项目简化
Former-commit-id: 73a4a6c9c41e013928e6205dd7c078d0e955f487
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^1.0.0",
|
||||
"@types/js-cookie": "^3.0.2",
|
||||
"@vueuse/core": "^9.1.1",
|
||||
"@wangeditor/editor": "^5.0.0",
|
||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||
@@ -19,6 +20,7 @@
|
||||
"default-passive-events": "^2.0.0",
|
||||
"echarts": "^5.2.2",
|
||||
"element-plus": "^2.2.5",
|
||||
"js-cookie": "^3.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
DeptFormData,
|
||||
DeptItem,
|
||||
DeptQueryParam
|
||||
} from '@/types/api/system/dept';
|
||||
import { DeptFormData, DeptItem, DeptQueryParam } from '@/types/api/dept';
|
||||
import { Option } from '@/types/common';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
@@ -16,7 +12,7 @@ export function listDepartments(
|
||||
queryParams?: DeptQueryParam
|
||||
): AxiosPromise<DeptItem[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/depts',
|
||||
url: '/youlai-system/api/v1/depts',
|
||||
method: 'get',
|
||||
params: queryParams
|
||||
});
|
||||
@@ -27,7 +23,7 @@ export function listDepartments(
|
||||
*/
|
||||
export function listDeptOptions(): AxiosPromise<Option[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/depts/options',
|
||||
url: '/youlai-system/api/v1/depts/options',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -39,7 +35,7 @@ export function listDeptOptions(): AxiosPromise<Option[]> {
|
||||
*/
|
||||
export function getDeptDetail(id: string): AxiosPromise<DeptFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/depts/' + id,
|
||||
url: '/youlai-system/api/v1/depts/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -51,7 +47,7 @@ export function getDeptDetail(id: string): AxiosPromise<DeptFormData> {
|
||||
*/
|
||||
export function addDept(data: DeptFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/depts',
|
||||
url: '/youlai-system/api/v1/depts',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
@@ -65,7 +61,7 @@ export function addDept(data: DeptFormData) {
|
||||
*/
|
||||
export function updateDept(id: string, data: DeptFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/depts/' + id,
|
||||
url: '/youlai-system/api/v1/depts/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
@@ -78,7 +74,7 @@ export function updateDept(id: string, data: DeptFormData) {
|
||||
*/
|
||||
export function deleteDept(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/depts/' + ids,
|
||||
url: '/youlai-system/api/v1/depts/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
DictItemPageResult,
|
||||
DictItemQueryParam,
|
||||
DictPageResult,
|
||||
DictQueryParam,
|
||||
} from '@/types/api/system/dict';
|
||||
DictQueryParam
|
||||
} from '@/types/api/dict';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
@@ -19,9 +19,9 @@ export function listPageDictTypes(
|
||||
queryParams: DictQueryParam
|
||||
): AxiosPromise<DictPageResult> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-types',
|
||||
url: '/youlai-system/api/v1/dict-types',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ export function listPageDictTypes(
|
||||
*/
|
||||
export function getDictFormData(id: number): AxiosPromise<DictFormTypeData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-types/' + id + '/form_data',
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/dict-types/' + id + '/form_data',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ export function getDictFormData(id: number): AxiosPromise<DictFormTypeData> {
|
||||
*/
|
||||
export function addDictType(data: DictFormTypeData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-types',
|
||||
url: '/youlai-system/api/v1/dict-types',
|
||||
method: 'post',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,9 +58,9 @@ export function addDictType(data: DictFormTypeData) {
|
||||
*/
|
||||
export function updateDictType(id: number, data: DictFormTypeData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-types/' + id,
|
||||
url: '/youlai-system/api/v1/dict-types/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,8 +71,8 @@ export function updateDictType(id: number, data: DictFormTypeData) {
|
||||
*/
|
||||
export function deleteDictTypes(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-types/' + ids,
|
||||
method: 'delete',
|
||||
url: '/youlai-system/api/v1/dict-types/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,9 +85,9 @@ export function listPageDictItems(
|
||||
queryParams: DictItemQueryParam
|
||||
): AxiosPromise<DictItemPageResult> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-items',
|
||||
url: '/youlai-system/api/v1/dict-items',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ export function getDictItemsByTypeCode(
|
||||
typeCode: string
|
||||
): AxiosPromise<Option[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-items/select_list',
|
||||
url: '/youlai-system/api/v1/dict-items/select_list',
|
||||
method: 'get',
|
||||
params: { typeCode: typeCode },
|
||||
params: { typeCode: typeCode }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,8 +113,8 @@ export function getDictItemsByTypeCode(
|
||||
*/
|
||||
export function getDictItemData(id: number): AxiosPromise<DictItemFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-items/' + id + '/form_data',
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/dict-items/' + id + '/form_data',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -125,9 +125,9 @@ export function getDictItemData(id: number): AxiosPromise<DictItemFormData> {
|
||||
*/
|
||||
export function addDictItem(data: DictItemFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-items',
|
||||
url: '/youlai-system/api/v1/dict-items',
|
||||
method: 'post',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -139,9 +139,9 @@ export function addDictItem(data: DictItemFormData) {
|
||||
*/
|
||||
export function updateDictItem(id: number, data: DictItemFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-items/' + id,
|
||||
url: '/youlai-system/api/v1/dict-items/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ export function updateDictItem(id: number, data: DictItemFormData) {
|
||||
*/
|
||||
export function deleteDictItems(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/dict-items/' + ids,
|
||||
method: 'delete',
|
||||
url: '/youlai-system/api/v1/dict-items/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -9,12 +9,12 @@ export function uploadFile(file: File) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/files',
|
||||
url: '/youlai-system/api/v1/files',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ export function uploadFile(file: File) {
|
||||
*/
|
||||
export function deleteFile(path?: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/files',
|
||||
url: '/youlai-system/api/v1/files',
|
||||
method: 'delete',
|
||||
params: { path: path },
|
||||
params: { path: path }
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
Captcha,
|
||||
LoginFormData,
|
||||
LoginResponseData,
|
||||
} from '@/types/api/system/login';
|
||||
import { Captcha, LoginFormData, LoginResponseData } from '@/types/api/login';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
@@ -16,8 +12,8 @@ export function login(data: LoginFormData): AxiosPromise<LoginResponseData> {
|
||||
method: 'post',
|
||||
params: data,
|
||||
headers: {
|
||||
Authorization: 'Basic bWFsbC1hZG1pbi13ZWI6MTIzNDU2', // 客户端信息Base64明文:mall-admin-web:123456
|
||||
},
|
||||
Authorization: 'Basic bWFsbC1hZG1pbi13ZWI6MTIzNDU2' // 客户端信息Base64明文:mall-admin-web:123456
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,7 +23,7 @@ export function login(data: LoginFormData): AxiosPromise<LoginResponseData> {
|
||||
export function logout() {
|
||||
return request({
|
||||
url: '/youlai-auth/oauth/logout',
|
||||
method: 'delete',
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -37,6 +33,6 @@ export function logout() {
|
||||
export function getCaptcha(): AxiosPromise<Captcha> {
|
||||
return request({
|
||||
url: '/captcha?t=' + new Date().getTime().toString(),
|
||||
method: 'get',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import {
|
||||
MenuFormData,
|
||||
MenuItem,
|
||||
MenuQueryParam,
|
||||
Resource,
|
||||
} from '@/types/api/system/menu';
|
||||
Resource
|
||||
} from '@/types/api/menu';
|
||||
import { Option } from '@/types/common';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
@@ -13,8 +13,8 @@ import { AxiosPromise } from 'axios';
|
||||
*/
|
||||
export function listRoutes() {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus/routes',
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/menus/routes',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ export function listMenus(
|
||||
queryParams: MenuQueryParam
|
||||
): AxiosPromise<MenuItem[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus',
|
||||
url: '/youlai-system/api/v1/menus',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ export function listMenus(
|
||||
*/
|
||||
export function listMenuOptions(): AxiosPromise<Option[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus/options',
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/menus/options',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ export function listMenuOptions(): AxiosPromise<Option[]> {
|
||||
*/
|
||||
export function listResources(): AxiosPromise<Resource[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus/resources',
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/menus/resources',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ export function listResources(): AxiosPromise<Resource[]> {
|
||||
*/
|
||||
export function getMenuDetail(id: string): AxiosPromise<MenuFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus/' + id,
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/menus/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,9 +71,9 @@ export function getMenuDetail(id: string): AxiosPromise<MenuFormData> {
|
||||
*/
|
||||
export function addMenu(data: MenuFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus',
|
||||
url: '/youlai-system/api/v1/menus',
|
||||
method: 'post',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -85,9 +85,9 @@ export function addMenu(data: MenuFormData) {
|
||||
*/
|
||||
export function updateMenu(id: string, data: MenuFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus/' + id,
|
||||
url: '/youlai-system/api/v1/menus/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ export function updateMenu(id: string, data: MenuFormData) {
|
||||
*/
|
||||
export function deleteMenus(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/menus/' + ids,
|
||||
method: 'delete',
|
||||
url: '/youlai-system/api/v1/menus/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { OrderPageResult, OrderQueryParam } from '@/types/api/oms/order';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取订单分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listOrderPages(
|
||||
queryParams: OrderQueryParam
|
||||
): AxiosPromise<OrderPageResult> {
|
||||
return request({
|
||||
url: '/mall-oms/api/v1/orders',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
*
|
||||
* @param orderId
|
||||
*/
|
||||
export function getOrderDetail(orderId: number) {
|
||||
return request({
|
||||
url: '/mall-oms/api/v1/orders/' + orderId,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取商品属性列表
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
export function listAttributes(params: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/attributes',
|
||||
method: 'get',
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量修改商品属性
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function saveAttributeBatch(data: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/attributes/batch',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import {
|
||||
BrandFormData,
|
||||
BrandItem,
|
||||
BrandPageResult,
|
||||
BrandQueryParam,
|
||||
} from '@/types/api/pms/brand';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取品牌分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listBrandPages(
|
||||
queryParams: BrandQueryParam
|
||||
): AxiosPromise<BrandPageResult> {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/brands/pages',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取品牌列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listBrands(
|
||||
queryParams?: BrandQueryParam
|
||||
): AxiosPromise<BrandItem[]> {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/brands',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取品牌详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getBrandFormDetail(id: number): AxiosPromise<BrandFormData> {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/brands/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加品牌
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addBrand(data: BrandFormData) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/brands',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改品牌
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateBrand(id: number, data: BrandFormData) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/brands/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除品牌
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deleteBrands(ids: string) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/brands/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
import { Option } from '@/types/common';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取商品分类列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listCategories(queryParams: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品分类级联器树形列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listCategoryOptions(): AxiosPromise<Option[]> {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/options',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品分类详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getCategoryDetail(id: number) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品分类
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addCategory(data: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品分类
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateCategory(id: number, data: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品分类
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deleteCategories(ids: string) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择性修改商品分类
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateCategoryPart(id: number, data: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/categories/' + id,
|
||||
method: 'patch',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import {
|
||||
GoodsDetail,
|
||||
GoodsPageResult,
|
||||
GoodsQueryParam,
|
||||
} from '@/types/api/pms/goods';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取商品分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listSpuPages(
|
||||
queryParams: GoodsQueryParam
|
||||
): AxiosPromise<GoodsPageResult> {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/spu/pages',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getSpuDetail(id: string): AxiosPromise<GoodsDetail> {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/spu/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addSpu(data: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/spu',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateSpu(id: number, data: object) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/spu/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deleteSpu(ids: string) {
|
||||
return request({
|
||||
url: '/mall-pms/api/v1/spu/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import {
|
||||
RoleFormData,
|
||||
RolePageResult,
|
||||
RoleQueryParam,
|
||||
RoleResource,
|
||||
} from '@/types/api/system/role';
|
||||
RoleResource
|
||||
} from '@/types/api/role';
|
||||
|
||||
import { Option } from '@/types/common';
|
||||
import request from '@/utils/request';
|
||||
@@ -18,9 +18,9 @@ export function listRolePages(
|
||||
queryParams?: RoleQueryParam
|
||||
): AxiosPromise<RolePageResult> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/pages',
|
||||
url: '/youlai-system/api/v1/roles/pages',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ export function listRoleOptions(
|
||||
queryParams?: RoleQueryParam
|
||||
): AxiosPromise<Option[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/options',
|
||||
url: '/youlai-system/api/v1/roles/options',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
params: queryParams
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ export function listRoleOptions(
|
||||
*/
|
||||
export function getRoleResources(roleId: string): AxiosPromise<RoleResource> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/' + roleId + '/resources',
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/roles/' + roleId + '/resources',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,9 +61,9 @@ export function updateRoleResource(
|
||||
data: RoleResource
|
||||
): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/' + roleId + '/resources',
|
||||
url: '/youlai-system/api/v1/roles/' + roleId + '/resources',
|
||||
method: 'put',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ export function updateRoleResource(
|
||||
*/
|
||||
export function getRoleFormDetail(id: number): AxiosPromise<RoleFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/' + id,
|
||||
method: 'get',
|
||||
url: '/youlai-system/api/v1/roles/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -86,9 +86,9 @@ export function getRoleFormDetail(id: number): AxiosPromise<RoleFormData> {
|
||||
*/
|
||||
export function addRole(data: RoleFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles',
|
||||
url: '/youlai-system/api/v1/roles',
|
||||
method: 'post',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ export function addRole(data: RoleFormData) {
|
||||
*/
|
||||
export function updateRole(id: number, data: RoleFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/' + id,
|
||||
url: '/youlai-system/api/v1/roles/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ export function updateRole(id: number, data: RoleFormData) {
|
||||
*/
|
||||
export function deleteRoles(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/roles/' + ids,
|
||||
method: 'delete',
|
||||
url: '/youlai-system/api/v1/roles/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import {
|
||||
AdvertFormData,
|
||||
AdvertPageResult,
|
||||
AdvertQueryParam,
|
||||
} from '@/types/api/sms/advert';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取广告分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listAdvertPages(
|
||||
queryParams: AdvertQueryParam
|
||||
): AxiosPromise<AdvertPageResult> {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/adverts/pages',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取广告详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getAdvertFormDetail(id: number): AxiosPromise<AdvertFormData> {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/adverts/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加广告
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addAdvert(data: AdvertFormData) {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/adverts',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改广告
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateAdvert(id: number, data: AdvertFormData) {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/adverts/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除广告
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deleteAdverts(ids: string) {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/adverts/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import {
|
||||
CouponQueryParam,
|
||||
CouponPageResult,
|
||||
CouponFormData,
|
||||
} from '@/types/api/sms/coupon';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取优惠券分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function lisCouponPages(
|
||||
queryParams: CouponQueryParam
|
||||
): AxiosPromise<CouponPageResult> {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/coupons/pages',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠券表单数据
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getCouponFormData(id: number): AxiosPromise<CouponFormData> {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/coupons/' + id + '/form_data',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加优惠券
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addCoupon(data: CouponFormData) {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/coupons',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改优惠券
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateCoupon(id: number, data: CouponFormData) {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/coupons/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除优惠券
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deleteCoupons(ids: string) {
|
||||
return request({
|
||||
url: '/mall-sms/api/v1/coupons/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import {
|
||||
ClientFormData,
|
||||
ClientPageResult,
|
||||
ClientQueryParam,
|
||||
} from '@/types/api/system/client';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listClientPages(
|
||||
queryParams: ClientQueryParam
|
||||
): AxiosPromise<ClientPageResult> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/oauth-clients',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
export function getClientFormDetial(id: number): AxiosPromise<ClientFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/oauth-clients/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export function addClient(data: ClientFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/oauth-clients',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateClient(id: string, data: ClientFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/oauth-clients/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteClients(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/oauth-clients/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
export function updateClientPart(id: number, data: object) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/oauth-clients/' + id,
|
||||
method: 'patch',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import {
|
||||
PermFormData,
|
||||
PermItem,
|
||||
PermPageResult,
|
||||
PermQueryParam,
|
||||
} from '@/types/api/system/perm';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取权限分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listPermPages(
|
||||
queryParams: PermQueryParam
|
||||
): AxiosPromise<PermPageResult> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/permissions/page',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listPerms(
|
||||
queryParams: PermQueryParam
|
||||
): AxiosPromise<PermItem[]> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/permissions',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getPermFormDetail(id: number): AxiosPromise<PermFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/permissions/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加权限
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addPerm(data: PermFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/permissions',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新权限
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updatePerm(id: number, data: PermFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/permissions/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除权限,多个以英文逗号(,)分割
|
||||
*
|
||||
* @param ids
|
||||
*/
|
||||
export function deletePerms(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/permissions/' + ids,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { MemberPageResult, MemberQueryParam } from '@/types/api/ums/member';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
/**
|
||||
* 获取会员分页列表
|
||||
*
|
||||
* @param queryParams
|
||||
*/
|
||||
export function listMemebersPage(
|
||||
queryParams: MemberQueryParam
|
||||
): AxiosPromise<MemberPageResult> {
|
||||
return request({
|
||||
url: '/mall-ums/api/v1/members',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员详情
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
export function getMemberDetail(id: number) {
|
||||
return request({
|
||||
url: '/mall-ums/api/v1/members/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加会员
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export function addMember(data: object) {
|
||||
return request({
|
||||
url: '/mall-ums/api/v1/members',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加会员
|
||||
*
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
export function updateMember(id: number, data: object) {
|
||||
return request({
|
||||
url: '/mall-ums/api/v1/members/' + id,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
@@ -5,14 +5,14 @@ import {
|
||||
UserInfo,
|
||||
UserPageResult,
|
||||
UserQueryParam
|
||||
} from '@/types/api/system/user';
|
||||
} from '@/types/api/user';
|
||||
|
||||
/**
|
||||
* 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)
|
||||
*/
|
||||
export function getUserInfo(): AxiosPromise<UserInfo> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/me',
|
||||
url: '/youlai-system/api/v1/users/me',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export function listUserPages(
|
||||
queryParams: UserQueryParam
|
||||
): AxiosPromise<UserPageResult> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/pages',
|
||||
url: '/youlai-system/api/v1/users/pages',
|
||||
method: 'get',
|
||||
params: queryParams
|
||||
});
|
||||
@@ -39,7 +39,7 @@ export function listUserPages(
|
||||
*/
|
||||
export function getUserDetail(userId: number): AxiosPromise<UserFormData> {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/' + userId,
|
||||
url: '/youlai-system/api/v1/users/' + userId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export function getUserDetail(userId: number): AxiosPromise<UserFormData> {
|
||||
*/
|
||||
export function addUser(data: any) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users',
|
||||
url: '/youlai-system/api/v1/users',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
@@ -65,7 +65,7 @@ export function addUser(data: any) {
|
||||
*/
|
||||
export function updateUser(id: number, data: UserFormData) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/' + id,
|
||||
url: '/youlai-system/api/v1/users/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
@@ -79,7 +79,7 @@ export function updateUser(id: number, data: UserFormData) {
|
||||
*/
|
||||
export function updateUserStatus(id: number, status: number) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/' + id + '/status',
|
||||
url: '/youlai-system/api/v1/users/' + id + '/status',
|
||||
method: 'patch',
|
||||
params: { status: status }
|
||||
});
|
||||
@@ -93,7 +93,7 @@ export function updateUserStatus(id: number, status: number) {
|
||||
*/
|
||||
export function updateUserPassword(id: number, password: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/' + id + '/password',
|
||||
url: '/youlai-system/api/v1/users/' + id + '/password',
|
||||
method: 'patch',
|
||||
params: { password: password }
|
||||
});
|
||||
@@ -106,7 +106,7 @@ export function updateUserPassword(id: number, password: string) {
|
||||
*/
|
||||
export function deleteUsers(ids: string) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/' + ids,
|
||||
url: '/youlai-system/api/v1/users/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -118,7 +118,7 @@ export function deleteUsers(ids: string) {
|
||||
*/
|
||||
export function downloadTemplate() {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/template',
|
||||
url: '/youlai-system/api/v1/users/template',
|
||||
method: 'get',
|
||||
responseType: 'arraybuffer'
|
||||
});
|
||||
@@ -132,7 +132,7 @@ export function downloadTemplate() {
|
||||
*/
|
||||
export function exportUser(queryParams: UserQueryParam) {
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/_export',
|
||||
url: '/youlai-system/api/v1/users/_export',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
responseType: 'arraybuffer'
|
||||
@@ -150,7 +150,7 @@ export function importUser(deptId: number, roleIds: string, file: File) {
|
||||
formData.append('deptId', deptId.toString());
|
||||
formData.append('roleIds', roleIds);
|
||||
return request({
|
||||
url: '/youlai-admin/api/v1/users/_import',
|
||||
url: '/youlai-system/api/v1/users/_import',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
UploadRawFile,
|
||||
UploadRequestOptions
|
||||
} from 'element-plus';
|
||||
import { uploadFile, deleteFile } from '@/api/system/file';
|
||||
import { uploadFile, deleteFile } from '@/api/file';
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import { onBeforeUnmount, shallowRef, reactive, toRefs } from 'vue';
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
|
||||
|
||||
// API 引用
|
||||
import { uploadFile } from '@/api/system/file';
|
||||
import { uploadFile } from '@/api/file';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
|
||||
@@ -21,14 +21,14 @@ import i18n from '@/lang/index';
|
||||
import '@/styles/index.scss';
|
||||
|
||||
// 根据字典编码获取字典列表全局方法
|
||||
import { getDictItemsByTypeCode } from '@/api/system/dict';
|
||||
import { getDictItemsByTypeCode } from '@/api/dict';
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
// 自定义指令
|
||||
import * as directive from '@/directive';
|
||||
|
||||
Object.keys(directive).forEach((key) => {
|
||||
Object.keys(directive).forEach(key => {
|
||||
app.directive(key, (directive as { [key: string]: Directive })[key]);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import router from '@/router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import useStore from '@/store';
|
||||
import { hasLogin } from '@/utils/auth';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
NProgress.configure({ showSpinner: false }); // 进度环显示/隐藏
|
||||
@@ -11,8 +12,8 @@ const whiteList = ['/login'];
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
const { user, permission } = useStore();
|
||||
const hasToken = user.token;
|
||||
if (hasToken) {
|
||||
|
||||
if (hasLogin()) {
|
||||
// 登录成功,跳转到首页
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' });
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PermissionState } from '@/types/store/permission';
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { defineStore } from 'pinia';
|
||||
import { constantRoutes } from '@/router';
|
||||
import { listRoutes } from '@/api/system/menu';
|
||||
import { listRoutes } from '@/api/menu';
|
||||
|
||||
const modules = import.meta.glob('../../views/**/**.vue');
|
||||
export const Layout = () => import('@/layout/index.vue');
|
||||
@@ -12,7 +12,7 @@ const hasPermission = (roles: string[], route: RouteRecordRaw) => {
|
||||
if (roles.includes('ROOT')) {
|
||||
return true;
|
||||
}
|
||||
return roles.some((role) => {
|
||||
return roles.some(role => {
|
||||
if (route.meta?.roles !== undefined) {
|
||||
return (route.meta.roles as string[]).includes(role);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export const filterAsyncRoutes = (
|
||||
roles: string[]
|
||||
) => {
|
||||
const res: RouteRecordRaw[] = [];
|
||||
routes.forEach((route) => {
|
||||
routes.forEach(route => {
|
||||
const tmp = { ...route } as any;
|
||||
if (hasPermission(roles, tmp)) {
|
||||
if (tmp.component == 'Layout') {
|
||||
@@ -53,7 +53,7 @@ const usePermissionStore = defineStore({
|
||||
id: 'permission',
|
||||
state: (): PermissionState => ({
|
||||
routes: [],
|
||||
addRoutes: [],
|
||||
addRoutes: []
|
||||
}),
|
||||
actions: {
|
||||
setRoutes(routes: RouteRecordRaw[]) {
|
||||
@@ -63,18 +63,18 @@ const usePermissionStore = defineStore({
|
||||
generateRoutes(roles: string[]) {
|
||||
return new Promise((resolve, reject) => {
|
||||
listRoutes()
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
const asyncRoutes = response.data;
|
||||
const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles);
|
||||
this.setRoutes(accessedRoutes);
|
||||
resolve(accessedRoutes);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default usePermissionStore;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { LoginFormData } from '@/types/api/system/login';
|
||||
import { LoginFormData } from '@/types/api/login';
|
||||
import { UserState } from '@/types/store/user';
|
||||
|
||||
import { localStorage } from '@/utils/storage';
|
||||
import { login, logout } from '@/api/login';
|
||||
import { getUserInfo } from '@/api/system/user';
|
||||
import { getUserInfo } from '@/api/user';
|
||||
import { resetRouter } from '@/router';
|
||||
|
||||
const useUserStore = defineStore({
|
||||
@@ -14,7 +14,7 @@ const useUserStore = defineStore({
|
||||
nickname: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
perms: [],
|
||||
perms: []
|
||||
}),
|
||||
actions: {
|
||||
async RESET_STATE() {
|
||||
@@ -31,16 +31,16 @@ const useUserStore = defineStore({
|
||||
password: password,
|
||||
grant_type: 'captcha',
|
||||
code: code,
|
||||
uuid: uuid,
|
||||
uuid: uuid
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
const { access_token, token_type } = response.data;
|
||||
const accessToken = token_type + ' ' + access_token;
|
||||
localStorage.set('token', accessToken);
|
||||
this.token = accessToken;
|
||||
resolve(access_token);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
@@ -65,7 +65,8 @@ const useUserStore = defineStore({
|
||||
this.perms = perms;
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
console.log('error', error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
@@ -83,7 +84,7 @@ const useUserStore = defineStore({
|
||||
resetRouter();
|
||||
resolve(null);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
@@ -93,13 +94,13 @@ const useUserStore = defineStore({
|
||||
* 清除 Token
|
||||
*/
|
||||
resetToken() {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
localStorage.remove('token');
|
||||
this.RESET_STATE();
|
||||
resolve(null);
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default useUserStore;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
import { PageQueryParam, PageResult } from './base';
|
||||
|
||||
/**
|
||||
* 字典查询参数类型声明
|
||||
56
src/types/api/oms/order.d.ts
vendored
56
src/types/api/oms/order.d.ts
vendored
@@ -1,56 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 订单查询参数类型声明
|
||||
*/
|
||||
export interface OrderQueryParam extends PageQueryParam {
|
||||
orderSn: string | undefined;
|
||||
status: number | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单分页列表项声明
|
||||
*/
|
||||
export interface Order {
|
||||
id: string;
|
||||
orderSn: string;
|
||||
totalAmount: string;
|
||||
payAmount: string;
|
||||
payType: number;
|
||||
status: number;
|
||||
totalQuantity: number;
|
||||
createTime: string;
|
||||
memberId: string;
|
||||
sourceType: number;
|
||||
orderItems: OrderItem[];
|
||||
}
|
||||
export interface OrderItem {
|
||||
id: string;
|
||||
orderId: string;
|
||||
skuId: string;
|
||||
skuName: string;
|
||||
picUrl: string;
|
||||
price: string;
|
||||
count: number;
|
||||
totalAmount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单分页项类型声明
|
||||
*/
|
||||
export type OrderPageResult = PageResult<Order[]>;
|
||||
|
||||
/**
|
||||
* 订单表单类型声明
|
||||
*/
|
||||
export interface OrderDetail {
|
||||
id: number | undefined;
|
||||
title: string;
|
||||
picUrl: string;
|
||||
beginTime: string;
|
||||
endTime: string;
|
||||
status: number;
|
||||
sort: number;
|
||||
url: string;
|
||||
remark: string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
import { PageQueryParam, PageResult } from './base';
|
||||
|
||||
/**
|
||||
* 权限查询参数类型声明
|
||||
33
src/types/api/pms/brand.d.ts
vendored
33
src/types/api/pms/brand.d.ts
vendored
@@ -1,33 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 品牌查询参数类型声明
|
||||
*/
|
||||
export interface BrandQueryParam extends PageQueryParam {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 品牌分页列表项声明
|
||||
*/
|
||||
export interface BrandItem {
|
||||
id: string;
|
||||
name: string;
|
||||
logoUrl: string;
|
||||
sort: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 品牌分页项类型声明
|
||||
*/
|
||||
export type BrandPageResult = PageResult<BrandItem[]>;
|
||||
|
||||
/**
|
||||
* 品牌表单类型声明
|
||||
*/
|
||||
export interface BrandFormData {
|
||||
id: number | undefined;
|
||||
name: string;
|
||||
logoUrl: string;
|
||||
sort: number;
|
||||
}
|
||||
70
src/types/api/pms/goods.d.ts
vendored
70
src/types/api/pms/goods.d.ts
vendored
@@ -1,70 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 商品查询参数类型声明
|
||||
*/
|
||||
export interface GoodsQueryParam extends PageQueryParam {
|
||||
name?: stirng;
|
||||
categoryId?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品列表项类型声明
|
||||
*/
|
||||
export interface GoodsItem {
|
||||
id: string;
|
||||
name: string;
|
||||
categoryId?: any;
|
||||
brandId?: any;
|
||||
originPrice: string;
|
||||
price: string;
|
||||
sales: number;
|
||||
picUrl?: any;
|
||||
album?: any;
|
||||
unit?: any;
|
||||
description: string;
|
||||
detail: string;
|
||||
status?: any;
|
||||
categoryName: string;
|
||||
brandName: string;
|
||||
skuList: SkuItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品规格项类型声明
|
||||
*/
|
||||
export interface SkuItem {
|
||||
id: string;
|
||||
skuSn?: any;
|
||||
name: string;
|
||||
spuId?: any;
|
||||
specIds: string;
|
||||
price: string;
|
||||
stockNum: number;
|
||||
lockedStockNum?: any;
|
||||
picUrl?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品分页项类型声明
|
||||
*/
|
||||
export type GoodsPageResult = PageResult<GoodsItem[]>;
|
||||
|
||||
/**
|
||||
* 商品表单数据类型声明
|
||||
*/
|
||||
export interface GoodsDetail {
|
||||
id?: string;
|
||||
name?: string;
|
||||
categoryId?: string;
|
||||
brandId?: string;
|
||||
originPrice?: number;
|
||||
price?: number;
|
||||
picUrl?: string;
|
||||
album: string[];
|
||||
description?: string;
|
||||
detail?: string;
|
||||
attrList: any[];
|
||||
specList: any[];
|
||||
skuList: any[];
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { StringMap } from 'i18next';
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
import { PageQueryParam, PageResult } from './base';
|
||||
|
||||
/**
|
||||
* 角色查询参数类型
|
||||
38
src/types/api/sms/advert.d.ts
vendored
38
src/types/api/sms/advert.d.ts
vendored
@@ -1,38 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 广告查询参数类型
|
||||
*/
|
||||
export interface AdvertQueryParam extends PageQueryParam {
|
||||
keywords: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 广告分页列表项
|
||||
*/
|
||||
export interface AdvertItem {
|
||||
id: string;
|
||||
name: string;
|
||||
logoUrl: string;
|
||||
sort: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 广告分页项类型
|
||||
*/
|
||||
export type AdvertPageResult = PageResult<AdvertItem[]>;
|
||||
|
||||
/**
|
||||
* 广告表单类型
|
||||
*/
|
||||
export interface AdvertFormData {
|
||||
id?: number;
|
||||
title: string;
|
||||
picUrl: string;
|
||||
beginTime: string;
|
||||
endTime: string;
|
||||
status: number;
|
||||
sort: number;
|
||||
url: string;
|
||||
remark: string;
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 优惠券查询参数类型
|
||||
*/
|
||||
export interface CouponQueryParam extends PageQueryParam {
|
||||
status?: number;
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优惠券分页列表项
|
||||
*/
|
||||
export interface CouponItem {
|
||||
id: string;
|
||||
name: string;
|
||||
code: string;
|
||||
platformLabel: string;
|
||||
typeLabel: string;
|
||||
faceValueLabel: string;
|
||||
validityPeriodLabel: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*优惠券分页
|
||||
*/
|
||||
export type CouponPageResult = PageResult<CouponItem[]>;
|
||||
|
||||
/**
|
||||
* 优惠券表单类型
|
||||
*/
|
||||
export interface CouponFormData {
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 优惠券名称
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 优惠券码
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* 使用平台(0:全平台;1:移动端;2:PC;)
|
||||
*/
|
||||
platform: number;
|
||||
/**
|
||||
* 优惠券类型(1:满减券;2:直减券;3:折扣券)
|
||||
*/
|
||||
type: number;
|
||||
|
||||
/**
|
||||
* 优惠券面值类型
|
||||
*/
|
||||
faceValueType: number;
|
||||
/**
|
||||
* 优惠券面值
|
||||
*/
|
||||
faceValue: number;
|
||||
/**
|
||||
* 优惠券折扣
|
||||
*/
|
||||
discount: number;
|
||||
/**
|
||||
* 发行量
|
||||
*/
|
||||
circulation: number;
|
||||
/**
|
||||
* 使用门槛(0:无门槛)
|
||||
*/
|
||||
minPoint: number;
|
||||
/**
|
||||
* 每人限领张数(-1:无限制)
|
||||
*/
|
||||
perLimit: number;
|
||||
/**
|
||||
* 有效期类型(1:日期范围;2:固定天数)
|
||||
*/
|
||||
validityPeriodType: number;
|
||||
/**
|
||||
* 自领取之日起有效天数
|
||||
*/
|
||||
validityDays: number;
|
||||
/**
|
||||
* 有效期起始时间
|
||||
*/
|
||||
validityBeginTime: string;
|
||||
/**
|
||||
* 有效期截止时间
|
||||
*/
|
||||
validityEndTime: string;
|
||||
/**
|
||||
* 应用范围(0:全场通用;1:指定商品分类;2:指定商品)
|
||||
*/
|
||||
applicationScope: number;
|
||||
|
||||
/**
|
||||
* 使用类型:指定商品分类
|
||||
*/
|
||||
spuCategoryIds: number[];
|
||||
|
||||
/**
|
||||
* 使用类型:指定商品
|
||||
*/
|
||||
spuIds: number[];
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
remark: string;
|
||||
}
|
||||
46
src/types/api/system/client.d.ts
vendored
46
src/types/api/system/client.d.ts
vendored
@@ -1,46 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 客户端查询参数类型
|
||||
*/
|
||||
export interface ClientQueryParam extends PageQueryParam {
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端分页列表项
|
||||
*/
|
||||
export interface ClientItem {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
resourceIds: string;
|
||||
scope: string;
|
||||
authorizedGrantTypes: string;
|
||||
webServerRedirectUri?: any;
|
||||
authorities?: any;
|
||||
accessTokenValidity: number;
|
||||
refreshTokenValidity: number;
|
||||
additionalInformation?: any;
|
||||
autoapprove: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端分页项类型
|
||||
*/
|
||||
export type ClientPageResult = PageResult<ClientItem[]>;
|
||||
|
||||
/**
|
||||
* 客户端表单类型
|
||||
*/
|
||||
export interface ClientFormData {
|
||||
authorizedGrantTypes: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
accessTokenValidity: string;
|
||||
refreshTokenValidity: string;
|
||||
webServerRedirectUri: string;
|
||||
authorities: string;
|
||||
additionalInformation: string;
|
||||
autoapprove: string;
|
||||
scope: string;
|
||||
}
|
||||
64
src/types/api/ums/member.d.ts
vendored
64
src/types/api/ums/member.d.ts
vendored
@@ -1,64 +0,0 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
|
||||
/**
|
||||
* 会员查询参数类型声明
|
||||
*/
|
||||
export interface MemberQueryParam extends PageQueryParam {
|
||||
nickName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员分页列表项声明
|
||||
*/
|
||||
export interface MemberItem {
|
||||
id: string;
|
||||
gender: number;
|
||||
nickName: string;
|
||||
mobile: string;
|
||||
birthday?: any;
|
||||
avatarUrl: string;
|
||||
openid: string;
|
||||
sessionKey?: any;
|
||||
city: string;
|
||||
country: string;
|
||||
language: string;
|
||||
province: string;
|
||||
status: number;
|
||||
balance: string;
|
||||
deleted: number;
|
||||
point: number;
|
||||
addressList: AddressItem[];
|
||||
}
|
||||
|
||||
export interface AddressItem {
|
||||
id: string;
|
||||
memberId: string;
|
||||
consigneeName: string;
|
||||
consigneeMobile: string;
|
||||
province: string;
|
||||
city: string;
|
||||
area: string;
|
||||
detailAddress: string;
|
||||
zipCode?: any;
|
||||
defaulted: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员分页项类型声明
|
||||
*/
|
||||
export type MemberPageResult = PageResult<MemberItem[]>;
|
||||
|
||||
/**
|
||||
* 会员表单类型声明
|
||||
*/
|
||||
export interface MemberFormData {
|
||||
id: number | undefined;
|
||||
title: string;
|
||||
picUrl: string;
|
||||
beginTime: string;
|
||||
endTime: string;
|
||||
status: number;
|
||||
sort: number;
|
||||
url: string;
|
||||
remark: string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageQueryParam, PageResult } from '../base';
|
||||
import { PageQueryParam, PageResult } from './base';
|
||||
|
||||
/**
|
||||
* 登录用户类型声明
|
||||
13
src/utils/auth.ts
Normal file
13
src/utils/auth.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
const SESSION_ID_KEY = 'SCG_SESSION_ID';
|
||||
|
||||
export const hasLogin = () => {
|
||||
const sessionId = Cookies.get(SESSION_ID_KEY);
|
||||
console.log('sessionId', sessionId);
|
||||
if (sessionId) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -53,7 +53,7 @@ service.interceptors.response.use(
|
||||
if (code === 'A0230') {
|
||||
// token 过期
|
||||
localStorage.clear(); // 清除浏览器全部缓存
|
||||
window.location.href = '/'; // 跳转登录页
|
||||
//window.location.href = '/'; // 跳转登录页
|
||||
ElMessageBox.alert('当前页面已失效,请重新登录', '提示', {});
|
||||
} else {
|
||||
ElMessage({
|
||||
|
||||
@@ -140,7 +140,7 @@ import useStore from '@/store';
|
||||
// API依赖
|
||||
import { getCaptcha } from '@/api/login';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { LoginFormData } from '@/types/api/system/login';
|
||||
import { LoginFormData } from '@/types/api/login';
|
||||
|
||||
const { user } = useStore();
|
||||
const route = useRoute();
|
||||
@@ -207,6 +207,9 @@ function showPwd() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* login
|
||||
*/
|
||||
function handleLogin() {
|
||||
loginFormRef.value.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
@@ -219,6 +222,8 @@ function handleLogin() {
|
||||
})
|
||||
.catch(() => {
|
||||
state.loading = false;
|
||||
|
||||
// 生成验证码
|
||||
handleCaptchaGenerate();
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'order',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Order, OrderQueryParam } from '@/types/api/oms/order';
|
||||
import { Dialog } from '@/types/common';
|
||||
|
||||
import { listOrderPages, getOrderDetail } from '@/api/oms/order';
|
||||
import { Search, Refresh } from '@element-plus/icons-vue';
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
|
||||
const orderSourceMap = {
|
||||
1: '微信小程序',
|
||||
2: 'APP',
|
||||
3: 'PC',
|
||||
};
|
||||
|
||||
const orderStatusMap = {
|
||||
101: '待付款',
|
||||
102: '用户取消',
|
||||
103: '系统取消',
|
||||
201: '已付款',
|
||||
202: '申请退款',
|
||||
203: '已退款',
|
||||
301: '待发货',
|
||||
401: '已发货',
|
||||
501: '用户收货',
|
||||
502: '系统收货',
|
||||
901: '已完成',
|
||||
};
|
||||
|
||||
const payTypeMap = {
|
||||
1: '支付宝',
|
||||
2: '微信',
|
||||
3: '会员余额',
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
dateRange: [] as any,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
} as OrderQueryParam,
|
||||
orderList: [] as Order[],
|
||||
total: 0,
|
||||
dialog: {
|
||||
title: '订单详情',
|
||||
visible: false,
|
||||
} as Dialog,
|
||||
dialogVisible: false,
|
||||
orderDetail: {
|
||||
order: {
|
||||
refundAmount: undefined,
|
||||
refundType: undefined,
|
||||
refundNote: undefined,
|
||||
gmtRefund: undefined,
|
||||
confirmTime: undefined,
|
||||
gmtDelivery: undefined,
|
||||
shipSn: undefined,
|
||||
shipChannel: undefined,
|
||||
gmtPay: undefined,
|
||||
integralPrice: undefined,
|
||||
payChannel: undefined,
|
||||
skuPrice: undefined,
|
||||
couponPrice: undefined,
|
||||
freightPrice: undefined,
|
||||
orderPrice: undefined,
|
||||
},
|
||||
member: {},
|
||||
orderItems: [],
|
||||
},
|
||||
orderSourceMap,
|
||||
orderStatusMap,
|
||||
payTypeMap,
|
||||
});
|
||||
|
||||
const { loading, queryParams, orderList, total, dateRange } = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listOrderPages(state.queryParams).then(({ data }) => {
|
||||
state.orderList = data.list;
|
||||
state.total = data.total;
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function viewDetail(row: any) {
|
||||
state.dialog.visible = true;
|
||||
getOrderDetail(row.id).then((response: any) => {
|
||||
state.orderDetail = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item prop="orderSn">
|
||||
<el-input v-model="queryParams.orderSn" placeholder="订单号" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
style="width: 240px"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
class="filter-item"
|
||||
placeholder="订单状态"
|
||||
>
|
||||
<el-option
|
||||
v-for="(key, value) in orderStatusMap"
|
||||
:key="key"
|
||||
:label="key"
|
||||
:value="value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table ref="dataTable" v-loading="loading" :data="orderList" border>
|
||||
<el-table-column type="expand" width="100" label="订单商品">
|
||||
<template #default="scope">
|
||||
<el-table :data="scope.row.orderItems" border>
|
||||
<el-table-column label="序号" type="index" width="100" />
|
||||
<el-table-column label="商品编号" align="center" prop="skuSn" />
|
||||
<el-table-column label="商品规格" align="center" prop="skuName" />
|
||||
<el-table-column label="图片" prop="picUrl">
|
||||
<template #default="scope">
|
||||
<img :src="scope.row.picUrl" width="40" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="单价" prop="price">
|
||||
<template #default="scope">{{ scope.row.price }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="数量" prop="count">
|
||||
<template #default="scope">{{ scope.row.count }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" prop="orderSn" label="订单编号" />
|
||||
|
||||
<el-table-column align="center" prop="memberId" label="会员ID" />
|
||||
|
||||
<el-table-column align="center" label="订单来源">
|
||||
<template #default="scope">
|
||||
<el-tag>{{ scope.row.sourceType }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="订单状态">
|
||||
<template #default="scope">
|
||||
<el-tag>{{ scope.row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" prop="orderPrice" label="订单金额">
|
||||
<template #default="scope">
|
||||
{{ scope.row.totalAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" prop="payPrice" label="支付金额">
|
||||
<template #default="scope">
|
||||
{{ scope.row.payAmount }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="支付方式">
|
||||
<template #default="scope">
|
||||
<el-tag>{{ scope.row.payType }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" prop="gmtCreate" label="创建时间" />
|
||||
|
||||
<el-table-column align="center" label="操作">
|
||||
<template #default="scope">
|
||||
<el-button @click="viewDetail(scope.row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页工具条 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,279 +0,0 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'brand',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { ElForm, ElTable, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import {
|
||||
BrandFormData,
|
||||
BrandItem,
|
||||
BrandQueryParam,
|
||||
} from '@/types/api/pms/brand';
|
||||
import { Dialog } from '@/types/common';
|
||||
import {
|
||||
listBrandPages,
|
||||
getBrandFormDetail,
|
||||
updateBrand,
|
||||
addBrand,
|
||||
deleteBrands,
|
||||
} from '@/api/pms/brand';
|
||||
import SingleUpload from '@/components/Upload/SingleUpload.vue';
|
||||
|
||||
const queryFormRef = ref(ElForm); // 属性名必须和元素的ref属性值一致
|
||||
const dataFormRef = ref(ElForm); // 属性名必须和元素的ref属性值一致
|
||||
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
// 选中ID数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
} as BrandQueryParam,
|
||||
brandList: [] as BrandItem[],
|
||||
total: 0,
|
||||
dialog: {} as Dialog,
|
||||
formData: { sort: 1 } as BrandFormData,
|
||||
rules: {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入品牌名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
multiple,
|
||||
queryParams,
|
||||
brandList,
|
||||
total,
|
||||
dialog,
|
||||
formData,
|
||||
rules,
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listBrandPages(state.queryParams).then(({ data }) => {
|
||||
state.brandList = data.list;
|
||||
state.total = data.total;
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection: any) {
|
||||
state.ids = selection.map((item: any) => item.id);
|
||||
state.single = selection.length !== 1;
|
||||
state.multiple = !selection.length;
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
state.dialog = {
|
||||
title: '添加品牌',
|
||||
visible: true,
|
||||
};
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
state.dialog = {
|
||||
title: '修改品牌',
|
||||
visible: true,
|
||||
};
|
||||
const brandId = row.id || state.ids;
|
||||
getBrandFormDetail(brandId).then(({ data }) => {
|
||||
state.formData = data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单提交
|
||||
*/
|
||||
function submitForm() {
|
||||
dataFormRef.value.validate((isValid: boolean) => {
|
||||
if (isValid) {
|
||||
if (state.formData.id) {
|
||||
updateBrand(state.formData.id, state.formData).then(() => {
|
||||
ElMessage.success('修改成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
addBrand(state.formData).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
function cancel() {
|
||||
state.dialog.visible = false;
|
||||
dataFormRef.value.resetFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
function handleDelete(row: any) {
|
||||
const ids = [row.id || state.ids].join(',');
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
deleteBrands(ids).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
handleQuery();
|
||||
});
|
||||
})
|
||||
.catch(() => ElMessage.info('已取消删除'));
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
click="handleDelete"
|
||||
:disabled="multiple"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="品牌名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="brandList"
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
>
|
||||
<el-table-column type="selection" min-width="5%" />
|
||||
<el-table-column prop="name" label="品牌名称" min-width="10" />
|
||||
<el-table-column prop="logoUrl" label="LOGO" min-width="10">
|
||||
<template #default="scope">
|
||||
<el-popover placement="right" :width="400" trigger="hover">
|
||||
<img :src="scope.row.logoUrl" width="400" height="400" />
|
||||
<template #reference>
|
||||
<img
|
||||
:src="scope.row.logoUrl"
|
||||
style="max-height: 60px; max-width: 60px"
|
||||
/>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="sort" label="排序" min-width="10" />
|
||||
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@click="handleUpdate(scope.row)"
|
||||
type="primary"
|
||||
:icon="Edit"
|
||||
circle
|
||||
plain
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click="handleDelete(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页工具条 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
|
||||
<!-- 表单弹窗 -->
|
||||
<el-dialog
|
||||
:title="dialog.title"
|
||||
v-model="dialog.visible"
|
||||
top="5vh"
|
||||
width="600px"
|
||||
>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="品牌名称" prop="name">
|
||||
<el-input v-model="formData.name" auto-complete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="LOGO" prop="logoUrl">
|
||||
<single-upload v-model="formData.logoUrl" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,183 +0,0 @@
|
||||
<template>
|
||||
<div class="component-container">
|
||||
<el-card class="box-card" shadow="always">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-tag type="success" v-if="category && category.name"
|
||||
>{{ category.name }} {{ attributeTypeName }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info"
|
||||
><i class="el-icon-info"></i> 请选择商品分类</el-tag
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="12" style="text-align: right">
|
||||
<el-button type="primary" :icon="Check" @click="submitForm"
|
||||
>提交</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row style="margin-top: 10px">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="formData"
|
||||
:disabled="category?.childrenLen > 0"
|
||||
label-width="100"
|
||||
>
|
||||
<el-form-item
|
||||
v-for="(item, index) in formData.attributes"
|
||||
:key="index"
|
||||
:label="attributeTypeName + (index + 1)"
|
||||
:prop="'attributes.' + index + '.name'"
|
||||
:rules="rules.attribute.name"
|
||||
>
|
||||
<el-input v-model="item.name" style="width: 300px" />
|
||||
|
||||
<el-button
|
||||
v-if="index === 0"
|
||||
type="success"
|
||||
:icon="Plus"
|
||||
circle
|
||||
plain
|
||||
@click.prevent="handleAdd()"
|
||||
style="margin-left: 15px"
|
||||
/>
|
||||
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
plain
|
||||
circle
|
||||
@click.prevent="handleDelete(index)"
|
||||
style="margin-left: 15px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, toRefs, watch } from 'vue';
|
||||
import { listAttributes, saveAttributeBatch } from '@/api/pms/attribute';
|
||||
import { Plus, Check, Delete } from '@element-plus/icons-vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
const props = defineProps({
|
||||
attributeType: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
category: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
id: undefined,
|
||||
name: '',
|
||||
childrenLen: 0,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const attributeTypeName = computed(() =>
|
||||
props.attributeType === 1 ? '规格' : '属性'
|
||||
);
|
||||
|
||||
const attributeNameValidator = (rule: any, value: any, callback: any) => {
|
||||
if (!value) {
|
||||
return callback(new Error('请输入' + attributeTypeName.value + '名称'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
formData: {
|
||||
categoryId: undefined,
|
||||
type: 1,
|
||||
attributes: [
|
||||
{
|
||||
id: undefined,
|
||||
name: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
rules: {
|
||||
attribute: {
|
||||
name: [
|
||||
{ required: true, validator: attributeNameValidator, trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { formData, rules } = toRefs(state);
|
||||
|
||||
watch(
|
||||
() => props.category.id as any,
|
||||
() => {
|
||||
const categoryId = props.category.id;
|
||||
if (categoryId) {
|
||||
listAttributes({
|
||||
categoryId: categoryId,
|
||||
type: props.attributeType,
|
||||
}).then((response) => {
|
||||
const { data } = response;
|
||||
if (data && data.length > 0) {
|
||||
state.formData.attributes = response.data;
|
||||
} else {
|
||||
state.formData.attributes = [
|
||||
{
|
||||
id: undefined,
|
||||
name: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
state.formData.attributes = [
|
||||
{
|
||||
id: undefined,
|
||||
name: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function handleAdd() {
|
||||
state.formData.attributes.push({
|
||||
id: undefined,
|
||||
name: '',
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(index: number) {
|
||||
if (state.formData.attributes.length == 1) {
|
||||
state.formData.attributes = [
|
||||
{
|
||||
id: undefined,
|
||||
name: '',
|
||||
},
|
||||
];
|
||||
return;
|
||||
}
|
||||
state.formData.attributes.splice(index, 1);
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
state.formData.categoryId = props.category.id;
|
||||
state.formData.type = props.attributeType;
|
||||
saveAttributeBatch(state.formData).then(() => {
|
||||
ElMessage.success('提交成功');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.component-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,289 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
listCategories,
|
||||
addCategory,
|
||||
updateCategory,
|
||||
deleteCategories,
|
||||
} from '@/api/pms/category';
|
||||
import { Plus, Edit, Delete, Picture } from '@element-plus/icons-vue';
|
||||
import SingleUpload from '@/components/Upload/SingleUpload.vue';
|
||||
import { onMounted, reactive, ref, toRefs, unref } from 'vue';
|
||||
import { ElForm, ElMessage, ElMessageBox, ElTree } from 'element-plus';
|
||||
|
||||
const emit = defineEmits(['categoryClick']);
|
||||
|
||||
const categoryTreeRef = ref(ElTree);
|
||||
const dataFormRef = ref(ElForm);
|
||||
|
||||
const state = reactive({
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
ids: [],
|
||||
queryParam: {},
|
||||
categoryOptions: [] as Array<any>,
|
||||
formData: {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
parentId: 0,
|
||||
level: undefined,
|
||||
iconUrl: undefined,
|
||||
visible: 1,
|
||||
sort: 100,
|
||||
},
|
||||
rules: {
|
||||
parentId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择上级分类',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入分类名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
dialog: {
|
||||
title: '',
|
||||
visible: false,
|
||||
},
|
||||
parent: {} as any,
|
||||
current: {} as any,
|
||||
});
|
||||
|
||||
const { loading, categoryOptions, formData, rules, dialog, parent } =
|
||||
toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listCategories(state.queryParam).then((response) => {
|
||||
state.categoryOptions = [
|
||||
{
|
||||
id: 0,
|
||||
name: '全部分类',
|
||||
parentId: 0,
|
||||
level: 0,
|
||||
children: response.data,
|
||||
},
|
||||
];
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleNodeClick(row: any) {
|
||||
const categoryTree = unref(categoryTreeRef);
|
||||
const parentNode = categoryTree.getNode(row.parentId);
|
||||
|
||||
state.parent = {
|
||||
id: parentNode.key,
|
||||
name: parentNode.label,
|
||||
level: row.level,
|
||||
};
|
||||
state.current = JSON.parse(JSON.stringify(row));
|
||||
emit('categoryClick', row);
|
||||
}
|
||||
|
||||
function handleAdd(row: any) {
|
||||
state.dialog = {
|
||||
title: '新增商品分类',
|
||||
visible: true,
|
||||
};
|
||||
if (row.id != null) {
|
||||
// 行点击新增
|
||||
state.parent = {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
level: row.level,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
handleNodeClick(row);
|
||||
state.dialog = {
|
||||
title: '修改商品分类',
|
||||
visible: true,
|
||||
};
|
||||
Object.assign(state.formData, state.current);
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
dataFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
if (state.formData.id) {
|
||||
updateCategory(state.formData.id, state.formData).then(() => {
|
||||
ElMessage.success('修改成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
const parentCategory = state.parent as any;
|
||||
console.log('parent', parentCategory);
|
||||
state.formData.parentId = parentCategory.id;
|
||||
state.formData.level = parentCategory.level + 1;
|
||||
|
||||
addCategory(state.formData).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(row: any) {
|
||||
const ids = [row.id || state.ids].join(',');
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
deleteCategories(ids).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
handleQuery();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
state.dialog.visible = false;
|
||||
dataFormRef.value.resetFields();
|
||||
state.dialog.visible = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 商品分类层级最多为三层,level字段标识 -->
|
||||
<template>
|
||||
<div class="component-container">
|
||||
<el-tree
|
||||
v-loading="loading"
|
||||
ref="categoryTreeRef"
|
||||
:data="categoryOptions"
|
||||
:props="{ label: 'name', children: 'children', disabled: '' }"
|
||||
node-key="id"
|
||||
:expand-on-click-node="false"
|
||||
default-expand-all
|
||||
:accordion="true"
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="custom-tree-node">
|
||||
<span>
|
||||
<el-image
|
||||
v-show="scope.data.level == 3"
|
||||
:src="scope.data.iconUrl"
|
||||
style="
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
margin-top: -5px;
|
||||
"
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<Picture style="width: 20px; height: 20px" />
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
{{ scope.data.name }}
|
||||
</span>
|
||||
<span>
|
||||
<el-button
|
||||
v-show="scope.data.level != 3"
|
||||
type="success"
|
||||
:icon="Plus"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleAdd(scope.data)"
|
||||
/>
|
||||
<el-button
|
||||
v-show="scope.data.id !== 0"
|
||||
type="warning"
|
||||
:icon="Edit"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleUpdate(scope.data)"
|
||||
/>
|
||||
<el-button
|
||||
v-show="
|
||||
scope.data.id &&
|
||||
(!scope.data.children || scope.data.children.length <= 0)
|
||||
"
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleDelete(scope.data)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="750px">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="上级分类" prop="parentId">
|
||||
<el-input v-model="parent.name" readonly />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input v-model="formData.name" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分类图标" prop="iconUrl">
|
||||
<single-upload v-model="formData.iconUrl" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="显示状态" prop="visible">
|
||||
<el-radio-group v-model="formData.visible">
|
||||
<el-radio :label="1">显示</el-radio>
|
||||
<el-radio :label="0">隐藏</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.component-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-right: 8px;
|
||||
line-height: 40px0;
|
||||
}
|
||||
|
||||
.el-tree-node__content {
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,79 +0,0 @@
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'category',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Category from './components/Category.vue';
|
||||
import Attribute from './components/Attribute.vue';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
|
||||
import { reactive, toRefs } from 'vue';
|
||||
|
||||
const state = reactive({
|
||||
category: {
|
||||
id: undefined,
|
||||
name: '',
|
||||
childrenLen: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const { category } = toRefs(state);
|
||||
|
||||
function handleCategoryClick(categoryRow: any) {
|
||||
if (categoryRow) {
|
||||
state.category = {
|
||||
id: categoryRow.id,
|
||||
name: categoryRow.name,
|
||||
childrenLen: categoryRow.children.length,
|
||||
};
|
||||
} else {
|
||||
state.category = {
|
||||
id: undefined,
|
||||
name: '',
|
||||
childrenLen: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="14" :xs="24">
|
||||
<el-card class="box-card" shadow="always">
|
||||
<template #header>
|
||||
<svg-icon icon-class="menu" />
|
||||
商品分类
|
||||
</template>
|
||||
<Category ref="categoryRef" @categoryClick="handleCategoryClick" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="10" :xs="24">
|
||||
<el-card class="box-card" shadow="always">
|
||||
<template #header>
|
||||
<svg-icon icon-class="menu" />
|
||||
{{ category.name }} 规格属性
|
||||
</template>
|
||||
<!-- 商品规格 -->
|
||||
<Attribute
|
||||
ref="specificationRef"
|
||||
:attributeType="1"
|
||||
:category="category"
|
||||
/>
|
||||
<!-- 商品属性 -->
|
||||
<Attribute
|
||||
ref="attributeRef"
|
||||
:attributeType="2"
|
||||
:category="category"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,178 +0,0 @@
|
||||
<template>
|
||||
<div class="component-container">
|
||||
<div class="component-container__main">
|
||||
<el-card class="box-card">
|
||||
<template #header>
|
||||
<span>商品属性</span>
|
||||
<el-button
|
||||
style="float: right"
|
||||
type="success"
|
||||
:icon="Plus"
|
||||
size="small"
|
||||
@click="handleAdd"
|
||||
>
|
||||
添加属性
|
||||
</el-button>
|
||||
</template>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="goodsInfo"
|
||||
:rules="rules"
|
||||
size="small"
|
||||
:inline="true"
|
||||
>
|
||||
<el-table
|
||||
:data="goodsInfo.attrList"
|
||||
size="small"
|
||||
highlight-current-row
|
||||
border
|
||||
>
|
||||
<el-table-column property="name" label="属性名称">
|
||||
<template #default="scope">
|
||||
<el-form-item
|
||||
:prop="'attrList[' + scope.$index + '].name'"
|
||||
:rules="rules.name"
|
||||
>
|
||||
<el-input v-model="scope.row.name" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column property="value" label="属性值">
|
||||
<template #default="scope">
|
||||
<el-form-item
|
||||
:prop="'attrList[' + scope.$index + '].value'"
|
||||
:rules="rules.value"
|
||||
>
|
||||
<el-input v-model="scope.row.value" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="150">
|
||||
<template #default="scope">
|
||||
<el-form-item>
|
||||
<el-button
|
||||
v-if="scope.$index > 0"
|
||||
type="danger"
|
||||
:icon="Minus"
|
||||
size="small"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleRemove(scope.$index)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="component-container__footer">
|
||||
<el-button @click="handlePrev">上一步,填写商品信息</el-button>
|
||||
<el-button type="primary" @click="handleNext"
|
||||
>下一步,设置商品库存</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, toRefs, watch } from 'vue';
|
||||
import { listAttributes } from '@/api/pms/attribute';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Plus, Minus } from '@element-plus/icons-vue';
|
||||
|
||||
const emit = defineEmits(['prev', 'next', 'update:modelValue']);
|
||||
const dataFormRef = ref(ElForm);
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const goodsInfo: any = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value);
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
() => goodsInfo.value.categoryId,
|
||||
(newVal) => {
|
||||
// 商品编辑不加载分类下的属性
|
||||
const goodsId = goodsInfo.value.id;
|
||||
if (goodsId) {
|
||||
return false;
|
||||
}
|
||||
// 商品新增加载默认分类下的属性
|
||||
if (newVal) {
|
||||
// type=2 商品分类下的属性
|
||||
listAttributes({ categoryId: newVal, type: 2 }).then((response) => {
|
||||
const attrList = response.data;
|
||||
if (attrList && attrList.length > 0) {
|
||||
goodsInfo.value.attrList = attrList;
|
||||
} else {
|
||||
goodsInfo.value.attrList = [{}];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
goodsInfo.value.attrList = [{}];
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
const state = reactive({
|
||||
rules: {
|
||||
name: [{ required: true, message: '请填写属性名称', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '请填写属性值', trigger: 'blur' }],
|
||||
},
|
||||
});
|
||||
|
||||
const { rules } = toRefs(state);
|
||||
|
||||
function handleAdd() {
|
||||
goodsInfo.value.attrList.push({});
|
||||
}
|
||||
|
||||
function handleRemove(index: number) {
|
||||
goodsInfo.value.attrList.splice(index, 1);
|
||||
}
|
||||
|
||||
function handlePrev() {
|
||||
emit('prev');
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
dataFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
emit('next');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.component-container {
|
||||
&__main {
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item--mini.el-form-item {
|
||||
margin-top: 18px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,113 +0,0 @@
|
||||
<template>
|
||||
<div class="component-container">
|
||||
<div class="component-container__main">
|
||||
<el-cascader-panel
|
||||
ref="categoryRef"
|
||||
:options="categoryOptions"
|
||||
v-model="goodsInfo.categoryId"
|
||||
:props="{ emitPath: false }"
|
||||
@change="handleCategoryChange"
|
||||
/>
|
||||
<div style="margin-top: 20px">
|
||||
<el-link type="info" :underline="false" v-show="pathLabels.length > 0"
|
||||
>您选择的商品分类:</el-link
|
||||
>
|
||||
<el-link
|
||||
type="danger"
|
||||
:underline="false"
|
||||
v-for="(item, index) in pathLabels"
|
||||
:key="index"
|
||||
style="margin-left: 5px"
|
||||
>
|
||||
{{ item }}
|
||||
<CaretRight
|
||||
v-show="index < pathLabels.length - 1"
|
||||
style="width: 1em; height: 1em; margin-left: 5px"
|
||||
/>
|
||||
</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="component-container__footer">
|
||||
<el-button type="primary" @click="handleNext"
|
||||
>下一步,填写商品信息</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, nextTick, reactive, ref, toRefs } from 'vue';
|
||||
import { ElCascaderPanel, ElMessage } from 'element-plus';
|
||||
import { CaretRight } from '@element-plus/icons-vue';
|
||||
|
||||
// API 引用
|
||||
import { listCategoryOptions } from '@/api/pms/category';
|
||||
import { computed } from 'vue';
|
||||
import { Option } from '@/types/common';
|
||||
|
||||
const emit = defineEmits(['next', 'update:modelValue']);
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const goodsInfo: any = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value);
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
categoryOptions: [] as Option[],
|
||||
pathLabels: [],
|
||||
});
|
||||
|
||||
const { categoryOptions, pathLabels } = toRefs(state);
|
||||
|
||||
function loadData() {
|
||||
listCategoryOptions().then(({ data }) => {
|
||||
state.categoryOptions = data;
|
||||
if (goodsInfo.value.id) {
|
||||
nextTick(() => {
|
||||
handleCategoryChange();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
const categoryRef = ref(ElCascaderPanel);
|
||||
|
||||
function handleCategoryChange() {
|
||||
const checkNode = categoryRef.value.getCheckedNodes()[0];
|
||||
state.pathLabels = checkNode.pathLabels; // 商品分类选择层级提示
|
||||
goodsInfo.value.categoryId = checkNode.value;
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
if (!goodsInfo.value.categoryId) {
|
||||
ElMessage.warning('请选择商品分类');
|
||||
return false;
|
||||
}
|
||||
emit('next');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.component-container {
|
||||
&__main {
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,220 +0,0 @@
|
||||
<template>
|
||||
<div class="component-container">
|
||||
<div class="component-container__main">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:rules="rules"
|
||||
:model="goodsInfo"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="商品品牌" prop="brandId">
|
||||
<el-select v-model="goodsInfo.brandId" style="width: 400px" clearable>
|
||||
<el-option
|
||||
v-for="item in brandOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input style="width: 400px" v-model="goodsInfo.name" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="原价" prop="originPrice">
|
||||
<el-input style="width: 400px" v-model="goodsInfo.originPrice" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="现价" prop="price">
|
||||
<el-input style="width: 400px" v-model="goodsInfo.price" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品简介">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||
v-model="goodsInfo.description"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品相册">
|
||||
<el-card
|
||||
v-for="(item, index) in pictures"
|
||||
:key="index"
|
||||
style="
|
||||
width: 170px;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
text-align: center;
|
||||
"
|
||||
:body-style="{ padding: '10px' }"
|
||||
>
|
||||
<single-upload v-model="item.url" :show-close="true" />
|
||||
|
||||
<div v-if="item.url">
|
||||
<el-link type="danger" class="button" v-if="item.main == true"
|
||||
>商品主图</el-link
|
||||
>
|
||||
<el-link
|
||||
type="info"
|
||||
class="button"
|
||||
v-else
|
||||
@click="changeMainPicture(index)"
|
||||
>设为主图</el-link
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<!-- 占位 -->
|
||||
<el-link type="info" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品详情" prop="detail">
|
||||
<editor v-model="goodsInfo.detail" style="height: 600px" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="component-container__footer">
|
||||
<el-button @click="handlePrev">上一步,选择商品分类</el-button>
|
||||
<el-button type="primary" @click="handleNext"
|
||||
>下一步,设置商品属性</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { ElForm } from 'element-plus';
|
||||
|
||||
// API 依赖
|
||||
import { listBrands } from '@/api/pms/brand';
|
||||
|
||||
// 自定义组件依赖
|
||||
import Editor from '@/components/WangEditor/index.vue';
|
||||
import SingleUpload from '@/components/Upload/SingleUpload.vue';
|
||||
|
||||
const emit = defineEmits(['prev', 'next', 'update:modelValue']);
|
||||
const dataFormRef = ref(ElForm);
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const goodsInfo: any = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value);
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
brandOptions: [] as Array<any>,
|
||||
// 商品图册
|
||||
pictures: [
|
||||
{ url: undefined, main: true }, // main为true代表主图,可切换
|
||||
{ url: undefined, main: false },
|
||||
{ url: undefined, main: false },
|
||||
{ url: undefined, main: false },
|
||||
{ url: undefined, main: false },
|
||||
] as Array<any>,
|
||||
rules: {
|
||||
name: [{ required: true, message: '请填写商品名称', trigger: 'blur' }],
|
||||
originPrice: [{ required: true, message: '请填写原价', trigger: 'blur' }],
|
||||
price: [{ required: true, message: '请填写现价', trigger: 'blur' }],
|
||||
brandId: [{ required: true, message: '请选择商品品牌', trigger: 'blur' }],
|
||||
},
|
||||
});
|
||||
|
||||
const { brandOptions, pictures, rules } = toRefs(state);
|
||||
|
||||
function loadData() {
|
||||
listBrands().then(({ data }) => {
|
||||
state.brandOptions = data;
|
||||
});
|
||||
const goodsId = goodsInfo.value.id;
|
||||
if (goodsId) {
|
||||
// 主图
|
||||
const mainPicUrl = goodsInfo.value.picUrl;
|
||||
if (mainPicUrl) {
|
||||
state.pictures.filter((item) => item.main)[0].url = mainPicUrl;
|
||||
}
|
||||
// 商品副图
|
||||
const subPicUrls = goodsInfo.value.subPicUrls;
|
||||
if (subPicUrls && subPicUrls.length > 0) {
|
||||
for (let i = 1; i <= subPicUrls.length; i++) {
|
||||
state.pictures[i].url = subPicUrls[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换主图
|
||||
*/
|
||||
function changeMainPicture(changeIndex: number) {
|
||||
const currMainPicture = JSON.parse(JSON.stringify(state.pictures[0]));
|
||||
const nextMainPicture = JSON.parse(
|
||||
JSON.stringify(state.pictures[changeIndex])
|
||||
);
|
||||
|
||||
state.pictures[0].url = nextMainPicture.url;
|
||||
state.pictures[changeIndex].url = currMainPicture.url;
|
||||
}
|
||||
|
||||
function handlePrev() {
|
||||
emit('prev');
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
dataFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
// 商品主图
|
||||
const mainPicUrl = state.pictures
|
||||
.filter((item) => item.main == true && item.url)
|
||||
.map((item) => item.url);
|
||||
if (mainPicUrl && mainPicUrl.length > 0) {
|
||||
goodsInfo.value.picUrl = mainPicUrl[0];
|
||||
}
|
||||
// 商品副图
|
||||
const subPicUrls = state.pictures
|
||||
.filter((item) => item.main == false && item.url)
|
||||
.map((item) => item.url);
|
||||
if (subPicUrls && subPicUrls.length > 0) {
|
||||
goodsInfo.value.subPicUrls = subPicUrls;
|
||||
} else {
|
||||
goodsInfo.value.subPicUrls = [];
|
||||
}
|
||||
emit('next');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.component-container {
|
||||
&__main {
|
||||
margin: 20px auto;
|
||||
|
||||
.button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,643 +0,0 @@
|
||||
<template>
|
||||
<div class="component-container">
|
||||
<div class="component-container__main">
|
||||
<el-card class="box-card">
|
||||
<template #header>
|
||||
<span>商品规格</span>
|
||||
<el-button
|
||||
:icon="Plus"
|
||||
type="success"
|
||||
@click="handleSpecAdd"
|
||||
size="small"
|
||||
style="float: right"
|
||||
>
|
||||
添加规格项
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<el-form
|
||||
ref="specFormRef"
|
||||
:model="specForm"
|
||||
:inline="true"
|
||||
size="small"
|
||||
>
|
||||
<el-table
|
||||
ref="specTableRef"
|
||||
:data="specForm.specList"
|
||||
row-key="id"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column align="center" width="50">
|
||||
<template>
|
||||
<svg-icon class="drag-handler" icon-class="drag" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格名" width="200">
|
||||
<template #default="scope">
|
||||
<el-form-item
|
||||
:prop="'specList[' + scope.$index + '].name'"
|
||||
:rules="rules.spec.name"
|
||||
>
|
||||
<el-input
|
||||
type="text"
|
||||
v-model="scope.row.name"
|
||||
size="small"
|
||||
@input="handleSpecChange()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column>
|
||||
<template #header>
|
||||
规格值
|
||||
<el-link
|
||||
type="danger"
|
||||
style="font-size: 12px"
|
||||
:underline="false"
|
||||
>(默认第一条规格包含图片)</el-link
|
||||
>
|
||||
</template>
|
||||
|
||||
<template #default="scope">
|
||||
<div
|
||||
v-for="item in scope.row.values"
|
||||
:key="item.id"
|
||||
style="margin-right: 15px; display: inline-block"
|
||||
>
|
||||
<el-tag
|
||||
size="small"
|
||||
closable
|
||||
:type="(colors[scope.$index % colors.length] as any)"
|
||||
@close="handleSpecValueRemove(scope.$index, item.id)"
|
||||
>
|
||||
{{ item.value }}
|
||||
</el-tag>
|
||||
<single-upload
|
||||
v-model="item.picUrl"
|
||||
v-if="scope.$index == 0"
|
||||
style="margin-top: 5px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-if="tagInputs.length > 0 && tagInputs[scope.$index].visible"
|
||||
v-model="tagInputs[scope.$index].value"
|
||||
@keyup.enter="handleSpecValueInput(scope.$index)"
|
||||
@blur="handleSpecValueInput(scope.$index)"
|
||||
style="width: 80px; vertical-align: top"
|
||||
size="small"
|
||||
/>
|
||||
<el-button
|
||||
v-else
|
||||
@click="handleSpecValueAdd(scope.$index)"
|
||||
:icon="Plus"
|
||||
style="vertical-align: top"
|
||||
size="small"
|
||||
>
|
||||
添加规格值
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="60" label="操作">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Minus"
|
||||
size="small"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleSpecRemove(scope.$index)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<template #header>
|
||||
<span>商品库存</span>
|
||||
</template>
|
||||
<el-form ref="skuFormRef" :model="skuForm" size="small" :inline="true">
|
||||
<el-table
|
||||
:data="skuForm.skuList"
|
||||
:span-method="(objectSpanMethod as any)"
|
||||
highlight-current-row
|
||||
size="small"
|
||||
border
|
||||
>
|
||||
<el-table-column
|
||||
v-for="(title, index) in specTitles"
|
||||
:key="index"
|
||||
align="center"
|
||||
:prop="'specValue' + (index + 1)"
|
||||
:label="title"
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="商品编码" align="center">
|
||||
<template #default="scope">
|
||||
<el-form-item
|
||||
:prop="'skuList[' + scope.$index + '].skuSn'"
|
||||
:rules="rules.sku.skuSn"
|
||||
>
|
||||
<el-input v-model="scope.row.skuSn" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="价格" align="center">
|
||||
<template #default="scope">
|
||||
<el-form-item
|
||||
:prop="'skuList[' + scope.$index + '].price'"
|
||||
:rules="rules.sku.price"
|
||||
>
|
||||
<el-input v-model="scope.row.price" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="库存" align="center">
|
||||
<template #default="scope">
|
||||
<el-form-item
|
||||
:prop="'skuList[' + scope.$index + '].stockNum'"
|
||||
:rules="rules.sku.stockNum"
|
||||
>
|
||||
<el-input v-model="scope.row.stockNum" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="component-container__footer">
|
||||
<el-button @click="handlePrev">上一步,设置商品属性</el-button>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref, toRefs, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Plus, Minus } from '@element-plus/icons-vue';
|
||||
import { ElNotification, ElMessage, ElTable, ElForm } from 'element-plus';
|
||||
|
||||
// API 引用
|
||||
import { listAttributes } from '@/api/pms/attribute';
|
||||
import { addSpu, updateSpu } from '@/api/pms/goods';
|
||||
|
||||
// 自定义组件引用
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import SingleUpload from '@/components/Upload/SingleUpload.vue';
|
||||
|
||||
const emit = defineEmits(['prev', 'next', 'update:modelValue']);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const specFormRef = ref(ElForm);
|
||||
const skuFormRef = ref(ElForm);
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const goodsInfo: any = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value);
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
specForm: {
|
||||
specList: [] as any[],
|
||||
},
|
||||
skuForm: {
|
||||
skuList: [] as any[],
|
||||
},
|
||||
// 规格项表格标题
|
||||
specTitles: [] as any[],
|
||||
rules: {
|
||||
spec: {
|
||||
name: [{ required: true, message: '请输入规格名称', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '请输入规格值', trigger: 'blur' }],
|
||||
},
|
||||
sku: {
|
||||
skuSn: [{ required: true, message: '请输入商品编号', trigger: 'blur' }],
|
||||
price: [{ required: true, message: '请输入商品价格', trigger: 'blur' }],
|
||||
stockNum: [
|
||||
{ required: true, message: '请输入商品库存', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
},
|
||||
colors: ['', 'success', 'warning', 'danger'],
|
||||
tagInputs: [{ value: undefined, visible: false }], // 规格值标签临时值和显隐控制
|
||||
});
|
||||
|
||||
const { specForm, skuForm, specTitles, rules, colors, tagInputs } =
|
||||
toRefs(state);
|
||||
|
||||
watch(
|
||||
() => goodsInfo.value.categoryId,
|
||||
(newVal) => {
|
||||
// 商品编辑不加载分类下的规格
|
||||
const goodsId = goodsInfo.value.id;
|
||||
if (goodsId) {
|
||||
return false;
|
||||
}
|
||||
if (newVal) {
|
||||
// type=1 商品分类下的规格
|
||||
listAttributes({ categoryId: newVal, type: 1 }).then((response) => {
|
||||
const specList = response.data;
|
||||
if (specList && specList.length > 0) {
|
||||
specList.forEach((item: any) => {
|
||||
state.specForm.specList.push({
|
||||
name: item.name,
|
||||
values: [],
|
||||
});
|
||||
});
|
||||
loadData();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(state.specForm.specList, () => {
|
||||
generateSkuList();
|
||||
});
|
||||
|
||||
function loadData() {
|
||||
goodsInfo.value.specList.forEach((specItem: any) => {
|
||||
const specIndex = state.specForm.specList.findIndex(
|
||||
(item: any) => item.name == specItem.name
|
||||
);
|
||||
if (specIndex > -1) {
|
||||
(state.specForm.specList[specIndex] as any).values.push({
|
||||
id: specItem.id,
|
||||
value: specItem.value,
|
||||
picUrl: specItem.picUrl,
|
||||
});
|
||||
} else {
|
||||
state.specForm.specList.push({
|
||||
name: specItem.name,
|
||||
values: [
|
||||
{ id: specItem.id, value: specItem.value, picUrl: specItem.picUrl },
|
||||
],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 每个规格项追加一个添加规格值按钮
|
||||
for (let i = 0; i < state.specForm.specList.length; i++) {
|
||||
state.tagInputs.push({ value: undefined, visible: false });
|
||||
}
|
||||
|
||||
// SKU规格ID拼接字符串处理
|
||||
goodsInfo.value.skuList.forEach((sku: any) => {
|
||||
sku.specIdArr = sku.specIds.split('_');
|
||||
});
|
||||
|
||||
generateSkuList();
|
||||
|
||||
handleSpecChange();
|
||||
|
||||
handleSpecReorder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成SKU列表的title
|
||||
*/
|
||||
function handleSpecChange() {
|
||||
const specList = JSON.parse(JSON.stringify(state.specForm.specList));
|
||||
state.specTitles = specList.map((item: any) => item.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 规格列表重排序
|
||||
*/
|
||||
function handleSpecReorder() {
|
||||
state.specForm.specList.forEach((item, index) => {
|
||||
item.index = index;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商品规格笛卡尔积生成SKU列表
|
||||
*
|
||||
* 规格列表:
|
||||
* [
|
||||
* { 'id':1,'name':'颜色','values':[{id:1,value:'白色'},{id:2,value:'黑色'},{id:3,value:'蓝色'}] },
|
||||
* { 'id':2,'name':'版本','values':[{id:1,value:'6+128G'},{id:2,value:'8+128G'},{id:3,value:'8G+256G'}] }
|
||||
* ]
|
||||
*/
|
||||
function generateSkuList() {
|
||||
// 如果规格为空,生成SKU列表为空
|
||||
if (state.specForm.specList.length == 0) {
|
||||
state.skuForm.skuList = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const specList = JSON.parse(
|
||||
JSON.stringify(
|
||||
state.specForm.specList.filter(
|
||||
(item) => item.values && item.values.length > 0
|
||||
)
|
||||
)
|
||||
); // 深拷贝,取有属性的规格项,否则笛卡尔积运算得到的SKU列表值为空
|
||||
|
||||
const skuList = specList.reduce(
|
||||
(acc: any, curr: any) => {
|
||||
let result = [] as any[];
|
||||
acc.forEach((item: any) => {
|
||||
// curr => { 'id':1,'name':'颜色','values':[{id:1,value:'白色'},{id:2,value:'黑色'},{id:3,value:'蓝色'}] }
|
||||
curr.values.forEach((v: any) => {
|
||||
// v=>{id:1,value:'白色'}
|
||||
let temp = Object.assign({}, item);
|
||||
temp.specValues += v.value + '_'; // 规格值拼接
|
||||
temp.specIds += v.id + '|'; // 规格ID拼接
|
||||
result.push(temp);
|
||||
});
|
||||
});
|
||||
return result;
|
||||
},
|
||||
[{ specValues: '', specIds: '' }]
|
||||
);
|
||||
|
||||
skuList.forEach((item: any) => {
|
||||
item.specIds = item.specIds.substring(0, item.specIds.length - 1);
|
||||
item.name = item.specValues
|
||||
.substring(0, item.specValues.length - 1)
|
||||
.replaceAll('_', ' ');
|
||||
const specIdArr = item.specIds.split('|');
|
||||
const skus = goodsInfo.value.skuList.filter(
|
||||
(sku: any) =>
|
||||
sku.specIdArr.length === specIdArr.length &&
|
||||
sku.specIdArr.every((a: any) => specIdArr.some((b: any) => a === b)) &&
|
||||
specIdArr.every((x: any) => sku.specIdArr.some((y: any) => x === y))
|
||||
); // 数据库的SKU列表
|
||||
|
||||
if (skus && skus.length > 0) {
|
||||
const sku = skus[0];
|
||||
item.id = sku.id;
|
||||
item.skuSn = sku.skuSn;
|
||||
item.price = sku.price / 100;
|
||||
item.stockNum = sku.stockNum;
|
||||
}
|
||||
const specValueArr = item.specValues
|
||||
.substring(0, item.specValues.length - 1)
|
||||
.split('_'); // ['黑','6+128G','官方标配']
|
||||
specValueArr.forEach((v: any, i: any) => {
|
||||
const key = 'specValue' + (i + 1);
|
||||
item[key] = v;
|
||||
if (i == 0 && state.specForm.specList.length > 0) {
|
||||
const valueIndex = state.specForm.specList[0].values.findIndex(
|
||||
(specValue: any) => specValue.value == v
|
||||
);
|
||||
if (valueIndex > -1) {
|
||||
item.picUrl = state.specForm.specList[0].values[valueIndex].picUrl;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
state.skuForm.skuList = JSON.parse(JSON.stringify(skuList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加规格
|
||||
*/
|
||||
function handleSpecAdd() {
|
||||
if (state.specForm.specList.length >= 3) {
|
||||
ElMessage.warning('最多支持3组规格');
|
||||
return;
|
||||
}
|
||||
state.specForm.specList.push({ values: [] });
|
||||
state.tagInputs.push({ value: undefined, visible: false });
|
||||
handleSpecReorder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除规格
|
||||
* @param index
|
||||
*/
|
||||
function handleSpecRemove(index: any) {
|
||||
state.specForm.specList.splice(index, 1);
|
||||
state.tagInputs.splice(index, 1);
|
||||
generateSkuList();
|
||||
handleSpecReorder();
|
||||
handleSpecChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加规格值
|
||||
*
|
||||
* @param specIndex
|
||||
*/
|
||||
function handleSpecValueAdd(specIndex: any) {
|
||||
state.tagInputs[specIndex].visible = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除规格值
|
||||
*
|
||||
* @param rowIndex
|
||||
* @param specValueId
|
||||
*/
|
||||
function handleSpecValueRemove(rowIndex: any, specValueId: any) {
|
||||
const specList = JSON.parse(JSON.stringify(state.specForm.specList));
|
||||
const removeIndex = specList[rowIndex].values
|
||||
.map((item: any) => item.id)
|
||||
.indexOf(specValueId);
|
||||
specList[rowIndex].values.splice(removeIndex, 1);
|
||||
state.specForm.specList = specList;
|
||||
generateSkuList();
|
||||
handleSpecChange();
|
||||
handleSpecReorder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 规格值输入
|
||||
*/
|
||||
function handleSpecValueInput(rowIndex: any) {
|
||||
const currSpecValue = state.tagInputs[rowIndex].value;
|
||||
const specValues = state.specForm.specList[rowIndex].values;
|
||||
if (
|
||||
specValues &&
|
||||
specValues.length > 0 &&
|
||||
specValues.map((item: any) => item.value).includes(currSpecValue)
|
||||
) {
|
||||
ElMessage.warning('规格值重复,请重新输入');
|
||||
return false;
|
||||
}
|
||||
if (currSpecValue) {
|
||||
if (specValues && specValues.length > 0) {
|
||||
// 临时规格值ID tid_1_1
|
||||
let maxSpecValueIndex = specValues
|
||||
.filter((item: any) => item.id.includes('tid_'))
|
||||
.map((item: any) => item.id.split('_')[2])
|
||||
.reduce((acc: any, curr: any) => {
|
||||
return acc > curr ? acc : curr;
|
||||
}, 0);
|
||||
state.specForm.specList[rowIndex].values[specValues.length] = {
|
||||
value: currSpecValue,
|
||||
id: 'tid_' + (rowIndex + 1) + '_' + ++maxSpecValueIndex,
|
||||
};
|
||||
} else {
|
||||
state.specForm.specList[rowIndex].values = [
|
||||
{ value: currSpecValue, id: 'tid_' + (rowIndex + 1) + '_1' },
|
||||
];
|
||||
}
|
||||
}
|
||||
state.tagInputs[rowIndex].value = undefined;
|
||||
state.tagInputs[rowIndex].visible = false;
|
||||
generateSkuList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并规格单元格
|
||||
*
|
||||
* @param cellObj 单元格对象
|
||||
*/
|
||||
|
||||
const objectSpanMethod = ({ rowIndex, columnIndex }: any) => {
|
||||
let mergeRows = [1, 1, 1]; // 分别对应规格1、规格2、规格3列合并的行数
|
||||
const specLen = state.specForm.specList.filter(
|
||||
(item) => item.values && item.values.length > 0
|
||||
).length;
|
||||
if (specLen == 2) {
|
||||
const values_len_2 = state.specForm.specList[1].values
|
||||
? state.specForm.specList[1].values.length
|
||||
: 1; // 第2个规格项的规格值的数量
|
||||
mergeRows = [values_len_2, 1, 1];
|
||||
} else if (specLen == 3) {
|
||||
const values_len_2 = state.specForm.specList[1].values
|
||||
? state.specForm.specList[1].values.length
|
||||
: 1; // 第2个规格项的规格值的数量
|
||||
const values_len_3 = state.specForm.specList[2].values
|
||||
? state.specForm.specList[2].values.length
|
||||
: 1; // 第3个规格项的规格值的数量
|
||||
mergeRows = [values_len_2 * values_len_3, values_len_3, 1];
|
||||
}
|
||||
if (columnIndex == 0) {
|
||||
if (rowIndex % mergeRows[0] === 0) {
|
||||
return [mergeRows[0], 1]; // 合并单元格
|
||||
} else {
|
||||
return [0, 0]; // 隐藏单元格
|
||||
}
|
||||
}
|
||||
if (columnIndex == 1) {
|
||||
if (rowIndex % mergeRows[1] === 0) {
|
||||
return [mergeRows[1], 1]; // 合并单元格
|
||||
} else {
|
||||
return [0, 0]; // 隐藏单元格
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 商品表单提交
|
||||
*/
|
||||
function submitForm() {
|
||||
// 判断商品SKU列表是否为空
|
||||
if (!state.skuForm.skuList || state.skuForm.skuList.length === 0) {
|
||||
ElMessage.warning('未添加商品库存');
|
||||
return false;
|
||||
}
|
||||
specFormRef.value.validate((specValid: any) => {
|
||||
if (specValid) {
|
||||
skuFormRef.value.validate((skuValid: any) => {
|
||||
if (skuValid) {
|
||||
// 重组商品的规格和SKU列表
|
||||
let submitsData = Object.assign({}, goodsInfo.value);
|
||||
delete submitsData.specList;
|
||||
delete submitsData.skuList;
|
||||
|
||||
let specList = [] as any[];
|
||||
state.specForm.specList.forEach((item) => {
|
||||
item.values.forEach((value: any) => {
|
||||
value.name = item.name;
|
||||
});
|
||||
specList = specList.concat(item.values);
|
||||
});
|
||||
submitsData.specList = specList; // 规格列表
|
||||
|
||||
submitsData.price *= 100; // 金额转成分保存至数据库
|
||||
submitsData.originPrice *= 100;
|
||||
|
||||
let skuList = JSON.parse(JSON.stringify(state.skuForm.skuList));
|
||||
skuList.map((item: any) => {
|
||||
item.price *= 100;
|
||||
return item;
|
||||
});
|
||||
submitsData.skuList = skuList;
|
||||
console.log('提交数据', submitsData);
|
||||
const goodsId = goodsInfo.value.id;
|
||||
if (goodsId) {
|
||||
// 编辑商品提交
|
||||
updateSpu(goodsId, submitsData).then(() => {
|
||||
router.push({ path: '/pms/goods' });
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '编辑商品成功',
|
||||
type: 'success',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 新增商品提交
|
||||
addSpu(submitsData).then(() => {
|
||||
router.push({ path: '/pms/goods' });
|
||||
ElNotification({
|
||||
title: '提示',
|
||||
message: '新增商品成功',
|
||||
type: 'success',
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handlePrev() {
|
||||
emit('prev');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.component-container {
|
||||
&__main {
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form--inline .el-form-item {
|
||||
margin-top: 18px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-steps
|
||||
:active="active"
|
||||
process-status="finish"
|
||||
finish-status="success"
|
||||
simple
|
||||
>
|
||||
<el-step title="选择商品分类" />
|
||||
<el-step title="填写商品信息" />
|
||||
<el-step title="设置商品属性" />
|
||||
<el-step title="设置商品库存" />
|
||||
</el-steps>
|
||||
|
||||
<GoodsCategory
|
||||
v-show="active == 0"
|
||||
v-model="goodsInfo"
|
||||
v-if="loaded == true"
|
||||
@prev="prev"
|
||||
@next="next"
|
||||
/>
|
||||
<GoodsInfo
|
||||
v-show="active == 1"
|
||||
v-model="goodsInfo"
|
||||
v-if="loaded == true"
|
||||
@prev="prev"
|
||||
@next="next"
|
||||
/>
|
||||
<GoodsAttribute
|
||||
v-show="active == 2"
|
||||
v-model="goodsInfo"
|
||||
v-if="loaded == true"
|
||||
@prev="prev"
|
||||
@next="next"
|
||||
/>
|
||||
<GoodsStock
|
||||
v-show="active == 3"
|
||||
v-model="goodsInfo"
|
||||
v-if="loaded == true"
|
||||
@prev="prev"
|
||||
@next="next"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, toRefs } from 'vue';
|
||||
|
||||
import GoodsCategory from './components/GoodsCategory.vue';
|
||||
import GoodsInfo from './components/GoodsInfo.vue';
|
||||
import GoodsAttribute from './components/GoodsAttribute.vue';
|
||||
import GoodsStock from './components/GoodsStock.vue';
|
||||
|
||||
import { getSpuDetail } from '@/api/pms/goods';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { GoodsDetail } from '@/types/api/pms/goods';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const state = reactive({
|
||||
loaded: false,
|
||||
active: 0,
|
||||
goodsInfo: {
|
||||
album: [],
|
||||
attrList: [],
|
||||
specList: [],
|
||||
skuList: [],
|
||||
} as GoodsDetail,
|
||||
});
|
||||
|
||||
const { loaded, active, goodsInfo } = toRefs(state);
|
||||
|
||||
function loadData() {
|
||||
const goodsId = route.query.goodsId as string;
|
||||
|
||||
if (goodsId) {
|
||||
getSpuDetail(goodsId).then((response) => {
|
||||
state.goodsInfo = response.data;
|
||||
state.goodsInfo.originPrice = (state.goodsInfo.originPrice as any) / 100;
|
||||
state.goodsInfo.price = (state.goodsInfo.price as any) / 100;
|
||||
state.loaded = true;
|
||||
});
|
||||
} else {
|
||||
state.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
function prev() {
|
||||
if (state.active-- <= 0) {
|
||||
state.active = 0;
|
||||
}
|
||||
}
|
||||
function next() {
|
||||
if (state.active++ >= 3) {
|
||||
state.active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-container {
|
||||
width: 1200px;
|
||||
margin: 50px auto;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
@@ -1,277 +0,0 @@
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'goods',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, onMounted, toRefs } from 'vue';
|
||||
import { ElTable, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import {
|
||||
Search,
|
||||
Position,
|
||||
Edit,
|
||||
Refresh,
|
||||
Delete,
|
||||
View,
|
||||
} from '@element-plus/icons-vue';
|
||||
import { listSpuPages, deleteSpu } from '@/api/pms/goods';
|
||||
import { listCategoryOptions } from '@/api/pms/category';
|
||||
import { GoodsItem, GoodsQueryParam } from '@/types/api/pms/goods';
|
||||
import { moneyFormatter } from '@/utils/filter';
|
||||
import { Option } from '@/types/common';
|
||||
|
||||
const dataTableRef = ref(ElTable);
|
||||
const router = useRouter();
|
||||
|
||||
const state = reactive({
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
} as GoodsQueryParam,
|
||||
goodsList: [] as GoodsItem[],
|
||||
categoryOptions: [] as Option[],
|
||||
goodDetail: undefined,
|
||||
dialogVisible: false,
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
multiple,
|
||||
queryParams,
|
||||
goodsList,
|
||||
categoryOptions,
|
||||
goodDetail,
|
||||
total,
|
||||
dialogVisible,
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listSpuPages(state.queryParams).then(({ data }) => {
|
||||
state.goodsList = data.list;
|
||||
state.total = data.total;
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
state.queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
name: undefined,
|
||||
categoryId: undefined,
|
||||
};
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleGoodsView(detail: any) {
|
||||
state.goodDetail = detail;
|
||||
state.dialogVisible = true;
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
router.push({ path: 'goods-detail' });
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
router.push({
|
||||
path: 'goods-detail',
|
||||
query: { goodsId: row.id, categoryId: row.categoryId },
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(row: any) {
|
||||
const ids = row.id || state.ids.join(',');
|
||||
ElMessageBox.confirm('是否确认删除选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(function () {
|
||||
return deleteSpu(ids);
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
|
||||
function handleRowClick(row: any) {
|
||||
dataTableRef.value.toggleRowSelection(row);
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection: any) {
|
||||
state.ids = selection.map((item: { id: any }) => item.id);
|
||||
state.single = selection.length != 1;
|
||||
state.multiple = !selection.length;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
listCategoryOptions().then(({ data }) => {
|
||||
categoryOptions.value = data;
|
||||
});
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryForm" :inline="true">
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Position" @click="handleAdd"
|
||||
>发布商品</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
@click="handleDelete"
|
||||
:disabled="multiple"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="商品名称"
|
||||
clearable
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-cascader
|
||||
v-model="queryParams.categoryId"
|
||||
placeholder="商品分类"
|
||||
:props="{ emitPath: false }"
|
||||
:options="categoryOptions"
|
||||
clearable
|
||||
style="width: 300px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>查询</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
ref="dataTableRef"
|
||||
v-loading="loading"
|
||||
:data="goodsList"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-click="handleRowClick"
|
||||
border
|
||||
>
|
||||
<el-table-column type="selection" min-width="5%" center />
|
||||
<el-table-column type="expand" width="120" label="库存信息">
|
||||
<template #default="props">
|
||||
<el-table :data="props.row.skuList" border>
|
||||
<el-table-column align="center" label="商品编码" prop="skuSn" />
|
||||
<el-table-column align="center" label="商品规格" prop="name" />
|
||||
<el-table-column label="图片" prop="picUrl">
|
||||
<template #default="scope">
|
||||
<img :src="scope.row.picUrl" width="40" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="现价" prop="price">
|
||||
<template #default="scope">{{
|
||||
moneyFormatter(scope.row.price)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="库存" prop="stockNum" />
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品名称" prop="name" min-width="140" />
|
||||
<el-table-column label="商品图片">
|
||||
<template #default="scope">
|
||||
<el-popover placement="right" :width="400" trigger="hover">
|
||||
<img :src="scope.row.picUrl" width="400" height="400" />
|
||||
<template #reference>
|
||||
<img
|
||||
:src="scope.row.picUrl"
|
||||
style="max-height: 60px; max-width: 60px"
|
||||
/>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品类目" prop="categoryName" min-width="100" />
|
||||
<el-table-column label="商品品牌" prop="brandName" min-width="100" />
|
||||
<el-table-column align="center" label="零售价" prop="originalPrice">
|
||||
<template #default="scope">{{
|
||||
moneyFormatter(scope.row.originPrice)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="促销价" prop="price">
|
||||
<template #default="scope">{{
|
||||
moneyFormatter(scope.row.price)
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="销量" prop="sales" min-width="100" />
|
||||
<el-table-column label="单位" prop="unit" min-width="100" />
|
||||
<el-table-column
|
||||
label="描述"
|
||||
prop="description"
|
||||
width="300"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column label="详情" prop="detail">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="View"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleGoodsView(scope.row.detail)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Edit"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleUpdate(scope.row)"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleDelete(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页工具条 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
<el-dialog v-model="dialogVisible" title="商品详情">
|
||||
<div class="goods-detail-box" v-html="goodDetail" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,306 +0,0 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'advert',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import SingleUpload from '@/components/Upload/SingleUpload.vue';
|
||||
import {
|
||||
listAdvertPages,
|
||||
getAdvertFormDetail,
|
||||
updateAdvert,
|
||||
addAdvert,
|
||||
deleteAdverts,
|
||||
} from '@/api/sms/advert';
|
||||
import { Dialog } from '@/types/common';
|
||||
import {
|
||||
AdvertFormData,
|
||||
AdvertItem,
|
||||
AdvertQueryParam,
|
||||
} from '@/types/api/sms/advert';
|
||||
|
||||
const queryFormRef = ref(ElForm); // 属性名必须和元素的ref属性值一致
|
||||
const dataFormRef = ref(ElForm); // 属性名必须和元素的ref属性值一致
|
||||
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
// 选中ID数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
queryParams: { pageNum: 1, pageSize: 10 } as AdvertQueryParam,
|
||||
advertList: [] as AdvertItem[],
|
||||
total: 0,
|
||||
dialog: { title: '', visible: false } as Dialog,
|
||||
formData: {
|
||||
status: 1,
|
||||
sort: 100,
|
||||
} as AdvertFormData,
|
||||
rules: {
|
||||
title: [{ required: true, message: '请输入广告名称', trigger: 'blur' }],
|
||||
picUrl: [{ required: true, message: '请上传广告图片', trigger: 'blur' }],
|
||||
},
|
||||
validityPeriod: '' as any,
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
multiple,
|
||||
queryParams,
|
||||
advertList,
|
||||
total,
|
||||
dialog,
|
||||
formData,
|
||||
rules,
|
||||
validityPeriod,
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listAdvertPages(state.queryParams).then(({ data }) => {
|
||||
state.advertList = data.list;
|
||||
state.total = data.total;
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection: any) {
|
||||
state.ids = selection.map((item: any) => item.id);
|
||||
state.single = selection.length !== 1;
|
||||
state.multiple = !selection.length;
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
state.dialog = {
|
||||
title: '添加广告',
|
||||
visible: true,
|
||||
};
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
state.dialog = {
|
||||
title: '修改广告',
|
||||
visible: true,
|
||||
};
|
||||
const advertId = row.id || state.ids;
|
||||
getAdvertFormDetail(advertId).then(({ data }) => {
|
||||
state.formData = data;
|
||||
validityPeriod.value = [data.beginTime, data.endTime];
|
||||
});
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
dataFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
const avertId = state.formData.id;
|
||||
if (avertId) {
|
||||
// 有效期转换
|
||||
if (validityPeriod.value) {
|
||||
formData.value.beginTime = validityPeriod.value[0];
|
||||
formData.value.endTime = validityPeriod.value[1];
|
||||
}
|
||||
|
||||
updateAdvert(avertId, state.formData).then(() => {
|
||||
ElMessage.success('修改成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
addAdvert(state.formData).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
state.formData.id = undefined;
|
||||
dataFormRef.value.resetFields();
|
||||
state.dialog.visible = false;
|
||||
}
|
||||
|
||||
function handleDelete(row: any) {
|
||||
const ids = [row.id || state.ids].join(',');
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
deleteAdverts(ids).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
handleQuery();
|
||||
});
|
||||
})
|
||||
.catch(() => ElMessage.info('已取消删除'));
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.keywords"
|
||||
placeholder="标题"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="advertList"
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
>
|
||||
<el-table-column type="selection" min-width="5" align="center" />
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="title" min-width="100" label="广告标题" />
|
||||
<el-table-column label="广告图片" width="100">
|
||||
<template #default="scope">
|
||||
<el-popover placement="right" :width="400" trigger="hover">
|
||||
<img :src="scope.row.picUrl" width="400" height="400" />
|
||||
<template #reference>
|
||||
<img
|
||||
:src="scope.row.picUrl"
|
||||
style="max-height: 60px; max-width: 60px"
|
||||
/>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="beginTime" label="开始时间" width="150" />
|
||||
<el-table-column prop="endTime" label="结束时间" width="150" />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status === 1" type="success">开启</el-tag>
|
||||
<el-tag v-else type="info">关闭</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sort" label="排序" width="80" />
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Edit"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleUpdate(scope.row)"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleDelete(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页工具条 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
|
||||
<!-- 表单弹窗 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="700px">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="广告标题" prop="title">
|
||||
<el-input v-model="formData.title" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效期">
|
||||
<el-date-picker
|
||||
v-model="validityPeriod"
|
||||
type="daterange"
|
||||
range-separator="~"
|
||||
start-placeholder="起始时间"
|
||||
end-placeholder="截止时间"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="广告图片" prop="picUrl">
|
||||
<single-upload v-model="formData.picUrl" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort" style="width: 200px" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="1">开启</el-radio>
|
||||
<el-radio :label="0">关闭</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="跳转链接" prop="url">
|
||||
<el-input v-model="formData.url" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" v-model="formData.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,532 +0,0 @@
|
||||
<!--优惠券-->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'coupon',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { ElForm, ElMessage, ElMessageBox, ElCascaderPanel } from 'element-plus';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import {
|
||||
lisCouponPages,
|
||||
getCouponFormData,
|
||||
updateCoupon,
|
||||
addCoupon,
|
||||
deleteCoupons,
|
||||
} from '@/api/sms/coupon';
|
||||
|
||||
import { listCategoryOptions } from '@/api/pms/category';
|
||||
import { listSpuPages } from '@/api/pms/goods';
|
||||
import { Dialog, Option } from '@/types/common';
|
||||
import {
|
||||
CouponItem,
|
||||
CouponQueryParam,
|
||||
CouponFormData,
|
||||
} from '@/types/api/sms/coupon';
|
||||
import { GoodsItem, GoodsQueryParam } from '@/types/api/pms/goods';
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dataFormRef = ref(ElForm);
|
||||
const spuCategoryRef = ref(ElCascaderPanel);
|
||||
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
queryParams: { pageNum: 1, pageSize: 10 } as CouponQueryParam,
|
||||
couponList: [] as CouponItem[],
|
||||
total: 0,
|
||||
dialog: {
|
||||
visible: false,
|
||||
} as Dialog,
|
||||
//指定商品分类选择Dialog
|
||||
spuCategoryChooseDialog: {
|
||||
visible: false,
|
||||
} as Dialog,
|
||||
// 指定商品选择ialog
|
||||
spuChooseDialog: {
|
||||
visible: false,
|
||||
} as Dialog,
|
||||
formData: {
|
||||
type: 1,
|
||||
platform: 0,
|
||||
validityPeriodType: 1,
|
||||
perLimit: 1,
|
||||
applicationScope: 0,
|
||||
} as CouponFormData,
|
||||
rules: {
|
||||
type: [{ required: true, message: '请输入优惠券名称', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '请选择优惠券类型', trigger: 'blur' }],
|
||||
},
|
||||
validityPeriod: '' as any,
|
||||
perLimitChecked: false,
|
||||
spuCategoryOptions: [] as Option[],
|
||||
spuCategoryProps: {
|
||||
multiple: true,
|
||||
emitPath: false,
|
||||
},
|
||||
spuList: [] as GoodsItem[],
|
||||
spuTotal: 0,
|
||||
spuQueryParams: { pageNum: 1, pageSize: 10 } as GoodsQueryParam,
|
||||
checkedSpuIds: [],
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
multiple,
|
||||
queryParams,
|
||||
couponList,
|
||||
total,
|
||||
dialog,
|
||||
formData,
|
||||
rules,
|
||||
validityPeriod,
|
||||
perLimitChecked,
|
||||
spuCategoryOptions,
|
||||
spuCategoryProps,
|
||||
spuList,
|
||||
spuTotal,
|
||||
checkedSpuIds,
|
||||
} = toRefs(state);
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
lisCouponPages(queryParams.value).then(({ data }) => {
|
||||
couponList.value = data.list;
|
||||
total.value = data.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 查询重置
|
||||
*/
|
||||
function resetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection: any) {
|
||||
state.ids = selection.map((item: any) => item.id);
|
||||
state.single = selection.length !== 1;
|
||||
state.multiple = !selection.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载商品分类
|
||||
*/
|
||||
async function loadSpuCategoryOptions() {
|
||||
listCategoryOptions().then(({ data }) => {
|
||||
spuCategoryOptions.value = data;
|
||||
});
|
||||
}
|
||||
|
||||
async function loadSpuList() {
|
||||
const queryParams = { pageNum: 1, pageSize: 10 } as GoodsQueryParam;
|
||||
listSpuPages(queryParams).then(({ data }) => {
|
||||
spuList.value = data.list;
|
||||
});
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
dialog.value = {
|
||||
title: '新增优惠券',
|
||||
visible: true,
|
||||
};
|
||||
|
||||
loadSpuCategoryOptions();
|
||||
loadSpuList();
|
||||
}
|
||||
|
||||
async function handleUpdate(row: any) {
|
||||
dialog.value = {
|
||||
title: '编辑优惠券',
|
||||
visible: true,
|
||||
};
|
||||
const id = row.id;
|
||||
|
||||
await loadSpuCategoryOptions();
|
||||
await loadSpuList();
|
||||
|
||||
getCouponFormData(id).then(({ data }) => {
|
||||
formData.value = data;
|
||||
perLimitChecked.value = data.perLimit == -1;
|
||||
// 有效期转换
|
||||
if (data.validityPeriodType == 1) {
|
||||
validityPeriod.value = [data.validityBeginTime, data.validityEndTime];
|
||||
}
|
||||
|
||||
// 金额转换分→元
|
||||
if (formData.value.faceValue) {
|
||||
formData.value.faceValue /= 100;
|
||||
}
|
||||
if (formData.value.minPoint) {
|
||||
formData.value.minPoint /= 100;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
dataFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
const applicationScope = formData.value.applicationScope;
|
||||
console.log('applicationScope', applicationScope);
|
||||
if (applicationScope == 1) {
|
||||
// 指定商品分类
|
||||
formData.value.spuCategoryIds =
|
||||
spuCategoryRef.value.getCheckedNodes()[0].data.value;
|
||||
}
|
||||
|
||||
// 有效期转换
|
||||
if (formData.value.validityPeriodType == 1 && validityPeriod.value) {
|
||||
formData.value.validityBeginTime = validityPeriod.value[0];
|
||||
formData.value.validityEndTime = validityPeriod.value[1];
|
||||
}
|
||||
// 金额转换元→分
|
||||
if (formData.value.faceValue) {
|
||||
formData.value.faceValue *= 100;
|
||||
}
|
||||
if (formData.value.faceValue) {
|
||||
formData.value.minPoint *= 100;
|
||||
}
|
||||
|
||||
const couponId = formData.value.id;
|
||||
if (couponId) {
|
||||
updateCoupon(couponId, formData.value).then(() => {
|
||||
ElMessage.success('编辑优惠券成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
addCoupon(formData.value).then(() => {
|
||||
ElMessage.success('新增优惠券成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
function cancel() {
|
||||
state.formData.id = undefined;
|
||||
dataFormRef.value.resetFields();
|
||||
state.dialog.visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除优惠券
|
||||
*/
|
||||
function handleDelete(row: any) {
|
||||
const ids = [row.id || state.ids].join(',');
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
deleteCoupons(ids).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
handleQuery();
|
||||
});
|
||||
})
|
||||
.catch(() => ElMessage.info('已取消删除'));
|
||||
}
|
||||
|
||||
function handleSpuQuery() {
|
||||
listSpuPages(queryParams.value).then(({ data }) => {
|
||||
spuList.value = data.list;
|
||||
spuTotal.value = data.total;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="keywords">
|
||||
<el-input
|
||||
v-model="queryParams.keywords"
|
||||
placeholder="优惠券名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="couponList"
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
>
|
||||
<el-table-column type="selection" min-width="5" align="center" />
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="name" min-width="100" label="优惠券名称" />
|
||||
<el-table-column prop="code" min-width="100" label="优惠券码" />
|
||||
<el-table-column prop="typeLabel" min-width="100" label="优惠券类型" />
|
||||
<el-table-column prop="faceValueLabel" min-width="100" label="面值" />
|
||||
<el-table-column prop="minPointLabel" min-width="100" label="使用门槛" />
|
||||
<el-table-column
|
||||
prop="validityPeriodLabel"
|
||||
min-width="200"
|
||||
label="有效期"
|
||||
/>
|
||||
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Edit"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleUpdate(scope.row)"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleDelete(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
|
||||
<!-- 表单Dialog -->
|
||||
<el-dialog
|
||||
:title="dialog.title"
|
||||
v-model="dialog.visible"
|
||||
width="1000px;"
|
||||
top="5vh"
|
||||
>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="150px"
|
||||
>
|
||||
<el-form-item label="优惠券类型" prop="type">
|
||||
<el-radio-group v-model="formData.type">
|
||||
<el-radio :label="1">满减券</el-radio>
|
||||
<el-radio :label="2">直减券</el-radio>
|
||||
<el-radio :label="3">折扣券</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="优惠券名称" prop="name">
|
||||
<el-input v-model="formData.name" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="优惠券面值" prop="faceValueType">
|
||||
<el-radio-group
|
||||
v-model="formData.faceValueType"
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<el-radio :label="1">现金</el-radio>
|
||||
<el-input
|
||||
v-model="formData.faceValue"
|
||||
:disabled="formData.faceValueType !== 1"
|
||||
placeholder="0.5-1000的数字"
|
||||
style="width: 180px"
|
||||
>
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div>
|
||||
<el-radio :label="2">折扣</el-radio>
|
||||
<el-input
|
||||
v-model="formData.discount"
|
||||
:disabled="formData.faceValueType !== 2"
|
||||
placeholder="1-9.9的数字"
|
||||
style="width: 180px"
|
||||
>
|
||||
<template #append>折</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="使用门槛" prop="minPoint">
|
||||
<el-input
|
||||
v-model="formData.minPoint"
|
||||
placeholder="0为无限制"
|
||||
style="width: 300px"
|
||||
>
|
||||
<template #prepend>满</template>
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效时间" prop="validType">
|
||||
<el-radio-group
|
||||
v-model="formData.validityPeriodType"
|
||||
style="display: flex; flex-direction: column"
|
||||
>
|
||||
<div>
|
||||
<el-radio :label="1">日期范围</el-radio>
|
||||
<el-date-picker
|
||||
v-model="validityPeriod"
|
||||
type="daterange"
|
||||
range-separator="~"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束时间"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:disabled="formData.validityPeriodType !== 1"
|
||||
/>
|
||||
</div>
|
||||
<div style="width: 100%">
|
||||
<el-radio :label="2">固定天数</el-radio>
|
||||
<el-input
|
||||
v-model="formData.validityDays"
|
||||
style="width: 150px"
|
||||
:disabled="formData.validityPeriodType !== 2"
|
||||
>
|
||||
<template #append>天</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="发行量" prop="circulation">
|
||||
<el-input
|
||||
v-model="formData.circulation"
|
||||
placeholder="-1为无限制"
|
||||
style="width: 200px"
|
||||
>
|
||||
<template #prepend>共</template>
|
||||
<template #append>张</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="每人限领张数" prop="perLimit">
|
||||
<el-input
|
||||
v-model="formData.perLimit"
|
||||
style="width: 200px"
|
||||
placeholder="-1为不限制"
|
||||
>
|
||||
<template #prepend>限</template>
|
||||
<template #append>张</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注信息" prop="remark">
|
||||
<el-input type="textarea" v-model="formData.remark" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品范围" prop="useType">
|
||||
<el-radio-group
|
||||
v-model="formData.applicationScope"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-radio :label="0">全场通用</el-radio>
|
||||
<el-radio :label="1">指定商品分类</el-radio>
|
||||
<el-radio :label="2">指定商品</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<div class="application-container">
|
||||
<!-- 指定商品分类 -->
|
||||
<el-cascader
|
||||
ref="spuCategoryRef"
|
||||
v-if="formData.applicationScope == 1"
|
||||
v-model="formData.spuCategoryIds"
|
||||
:options="spuCategoryOptions"
|
||||
:props="spuCategoryProps"
|
||||
:show-all-levels="true"
|
||||
style="width: 450px"
|
||||
/>
|
||||
|
||||
<el-transfer
|
||||
class="application-container__transfer"
|
||||
v-model="formData.spuIds"
|
||||
v-if="formData.applicationScope == 2"
|
||||
filterable
|
||||
filter-placeholder="商品名称/编码"
|
||||
:data="spuList"
|
||||
:titles="['商品列表', '已选择商品']"
|
||||
:props="{
|
||||
key: 'id',
|
||||
label: 'name',
|
||||
}"
|
||||
>
|
||||
<template #left-footer>
|
||||
<pagination
|
||||
:total="spuTotal"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleSpuQuery"
|
||||
layout="prev, pager, next,"
|
||||
/>
|
||||
</template>
|
||||
</el-transfer>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.application-container {
|
||||
margin-top: 20px;
|
||||
|
||||
&__transfer {
|
||||
.pagination-container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,374 +0,0 @@
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'client',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
listClientPages,
|
||||
getClientFormDetial,
|
||||
addClient,
|
||||
updateClient,
|
||||
deleteClients,
|
||||
} from '@/api/system/client';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import { onMounted, reactive, getCurrentInstance, ref, toRefs } from 'vue';
|
||||
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import {
|
||||
ClientFormData,
|
||||
ClientItem,
|
||||
ClientQueryParam,
|
||||
} from '@/types/api/system/client';
|
||||
import { Option } from '@/types/common';
|
||||
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dataFormRef = ref(ElForm);
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
// 选中ID数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
} as ClientQueryParam,
|
||||
clientList: [] as ClientItem[],
|
||||
total: 0,
|
||||
dialog: {
|
||||
title: '',
|
||||
visible: false,
|
||||
type: 'create',
|
||||
},
|
||||
formData: {} as ClientFormData,
|
||||
rules: {
|
||||
clientId: [
|
||||
{ required: true, message: '客户端ID不能为空', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
authorizedGrantTypesOptions: [] as Option[],
|
||||
checkedAuthorizedGrantTypes: [] as string[],
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
ids,
|
||||
multiple,
|
||||
queryParams,
|
||||
clientList,
|
||||
total,
|
||||
dialog,
|
||||
formData,
|
||||
rules,
|
||||
authorizedGrantTypesOptions,
|
||||
checkedAuthorizedGrantTypes,
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
listClientPages(state.queryParams).then(({ data }) => {
|
||||
state.clientList = data.list;
|
||||
state.total = data.total;
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection: any) {
|
||||
state.ids = selection.map((item: any) => item.clientId);
|
||||
state.single = selection.length !== 1;
|
||||
state.multiple = !selection.length;
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
proxy.$getDictItemsByTypeCode('grant_type').then((response: any) => {
|
||||
state.authorizedGrantTypesOptions = response.data;
|
||||
});
|
||||
|
||||
state.dialog = {
|
||||
title: '添加客户端',
|
||||
visible: true,
|
||||
type: 'create',
|
||||
};
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
state.dialog = {
|
||||
title: '修改客户端',
|
||||
visible: true,
|
||||
type: 'edit',
|
||||
};
|
||||
const clientId = row.clientId || ids;
|
||||
|
||||
proxy.$getDictItemsByTypeCode('grant_type').then((res: any) => {
|
||||
state.authorizedGrantTypesOptions = res.data;
|
||||
|
||||
getClientFormDetial(clientId).then(({ data }) => {
|
||||
state.formData = data;
|
||||
state.checkedAuthorizedGrantTypes = data.authorizedGrantTypes?.split(',');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
dataFormRef.value.validate((isvalid: boolean) => {
|
||||
if (isvalid) {
|
||||
state.formData.authorizedGrantTypes =
|
||||
state.checkedAuthorizedGrantTypes.join(',');
|
||||
if (state.dialog.type == 'edit') {
|
||||
updateClient(state.formData.clientId, state.formData).then(() => {
|
||||
ElMessage.success('修改成功');
|
||||
state.dialog.visible = false;
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
addClient(state.formData).then(() => {
|
||||
ElMessage.success('新增成功');
|
||||
cancel();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
state.dialog.visible = false;
|
||||
dataFormRef.value.resetFields();
|
||||
state.checkedAuthorizedGrantTypes = [];
|
||||
}
|
||||
|
||||
function handleDelete(row: any) {
|
||||
const clientIds = [row.clientId || ids].join(',');
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
deleteClients(clientIds).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
handleQuery();
|
||||
});
|
||||
})
|
||||
.catch(() => ElMessage.info('已取消删除'));
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||
>新增</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="queryParams.keywords"
|
||||
placeholder="客户端ID"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="clientList"
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
<el-table-column label="客户端ID" prop="clientId" width="200" />
|
||||
<el-table-column label="客户端密钥" prop="clientSecret" width="100" />
|
||||
<el-table-column label="域" width="100" prop="scope" />
|
||||
<el-table-column label="自动放行" prop="autoapprove" width="100" />
|
||||
<el-table-column label="授权方式" prop="authorizedGrantTypes" />
|
||||
<el-table-column
|
||||
label="认证令牌时效(单位:秒)"
|
||||
width="200"
|
||||
prop="accessTokenValidity"
|
||||
/>
|
||||
<el-table-column
|
||||
label="刷新令牌时效(单位:秒)"
|
||||
width="200"
|
||||
prop="refreshTokenValidity"
|
||||
/>
|
||||
<el-table-column label="操作" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Edit"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleUpdate(scope.row)"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
plain
|
||||
@click.stop="handleDelete(scope.row)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页工具条 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
|
||||
<!-- 表单弹窗 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="700px">
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户端ID" prop="clientId">
|
||||
<el-input
|
||||
v-model="formData.clientId"
|
||||
placeholder="请输入客户端ID"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户端密钥" prop="clientSecret">
|
||||
<el-input
|
||||
v-model="formData.clientSecret"
|
||||
placeholder="请输入客户端密钥"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="域" prop="scope">
|
||||
<el-input v-model="formData.scope" placeholder="请输入域" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="自动放行" prop="autoapprove">
|
||||
<el-radio-group v-model="formData.autoapprove">
|
||||
<el-radio label="true">是</el-radio>
|
||||
<el-radio label="false">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="授权方式" prop="authorizedGrantTypes">
|
||||
<el-checkbox-group v-model="checkedAuthorizedGrantTypes">
|
||||
<el-checkbox
|
||||
v-for="item in authorizedGrantTypesOptions"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
>{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="认证令牌时效" prop="accessTokenValidity">
|
||||
<el-input
|
||||
v-model="formData.accessTokenValidity"
|
||||
placeholder="请输入认证令牌时效"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="刷新令牌时效" prop="refreshTokenValidity">
|
||||
<el-input
|
||||
v-model="formData.refreshTokenValidity"
|
||||
placeholder="请输入刷新令牌时效"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="回调地址" prop="webServerRedirectUri">
|
||||
<el-input
|
||||
v-model="formData.webServerRedirectUri"
|
||||
placeholder="请输入回调地址"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="权限" prop="authorities">
|
||||
<el-input
|
||||
v-model="formData.authorities"
|
||||
placeholder="请输入权限"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="扩展信息" prop="additionalInformation">
|
||||
<el-input
|
||||
v-model="formData.additionalInformation"
|
||||
type="textarea"
|
||||
placeholder="JSON格式"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm"> 确定 </el-button>
|
||||
<el-button @click="cancel"> 取消 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -16,16 +16,12 @@ import {
|
||||
addDept,
|
||||
listDeptOptions,
|
||||
listDepartments
|
||||
} from '@/api/system/dept';
|
||||
} from '@/api/dept';
|
||||
|
||||
// 组件依赖
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import {
|
||||
DeptFormData,
|
||||
DeptItem,
|
||||
DeptQueryParam
|
||||
} from '@/types/api/system/dept';
|
||||
import { DeptFormData, DeptItem, DeptQueryParam } from '@/types/api/dept';
|
||||
import { Dialog, Option } from '@/types/common';
|
||||
|
||||
// DOM元素的引用声明定义
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'dictItem',
|
||||
name: 'dictItem'
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -10,8 +10,8 @@ import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import {
|
||||
DictItem,
|
||||
DictItemFormData,
|
||||
DictItemQueryParam,
|
||||
} from '@/types/api/system/dict';
|
||||
DictItemQueryParam
|
||||
} from '@/types/api/dict';
|
||||
|
||||
import { Dialog } from '@/types/common';
|
||||
import {
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
getDictItemData,
|
||||
addDictItem,
|
||||
updateDictItem,
|
||||
deleteDictItems,
|
||||
} from '@/api/system/dict';
|
||||
deleteDictItems
|
||||
} from '@/api/dict';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -28,19 +28,19 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: () => {
|
||||
return '';
|
||||
},
|
||||
}
|
||||
},
|
||||
typeName: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return '';
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.typeCode,
|
||||
(value) => {
|
||||
value => {
|
||||
state.queryParams.typeCode = value;
|
||||
state.formData.typeCode = value;
|
||||
handleQuery();
|
||||
@@ -66,14 +66,14 @@ const state = reactive({
|
||||
typeCode: props.typeCode,
|
||||
typeName: props.typeName,
|
||||
status: 1,
|
||||
sort: 1,
|
||||
sort: 1
|
||||
} as DictItemFormData,
|
||||
rules: {
|
||||
name: [{ required: true, message: '请输入字典项名称', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '请输入字典项值', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '请输入字典项值', trigger: 'blur' }]
|
||||
},
|
||||
localDictCode: props.typeCode,
|
||||
localDictName: props.typeName,
|
||||
localDictName: props.typeName
|
||||
});
|
||||
|
||||
const {
|
||||
@@ -84,7 +84,7 @@ const {
|
||||
dialog,
|
||||
formData,
|
||||
rules,
|
||||
total,
|
||||
total
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
@@ -121,14 +121,14 @@ function handleAdd() {
|
||||
}
|
||||
state.dialog = {
|
||||
title: '添加字典数据项',
|
||||
visible: true,
|
||||
visible: true
|
||||
};
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
state.dialog = {
|
||||
title: '修改字典数据项',
|
||||
visible: true,
|
||||
visible: true
|
||||
};
|
||||
const id = row.id || state.ids;
|
||||
getDictItemData(id).then(({ data }) => {
|
||||
@@ -167,7 +167,7 @@ function handleDelete(row: any) {
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
deleteDictItems(ids).then(() => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'dictType',
|
||||
name: 'dictType'
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -135,17 +135,13 @@ import {
|
||||
getDictFormData,
|
||||
addDictType,
|
||||
updateDictType,
|
||||
deleteDictTypes,
|
||||
} from '@/api/system/dict';
|
||||
deleteDictTypes
|
||||
} from '@/api/dict';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
import { Dialog } from '@/types/common';
|
||||
import {
|
||||
Dict,
|
||||
DictFormTypeData,
|
||||
DictQueryParam,
|
||||
} from '@/types/api/system/dict';
|
||||
import { Dict, DictFormTypeData, DictQueryParam } from '@/types/api/dict';
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dataFormRef = ref(ElForm);
|
||||
@@ -162,18 +158,18 @@ const state = reactive({
|
||||
multiple: true,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 10
|
||||
} as DictQueryParam,
|
||||
dictList: [] as Dict[],
|
||||
total: 0,
|
||||
dialog: { visible: false } as Dialog,
|
||||
formData: {
|
||||
status: 1,
|
||||
status: 1
|
||||
} as DictFormTypeData,
|
||||
rules: {
|
||||
name: [{ required: true, message: '请输入字典名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入字典编码', trigger: 'blur' }],
|
||||
},
|
||||
code: [{ required: true, message: '请输入字典编码', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
const { total, dialog, loading, dictList, formData, rules, queryParams } =
|
||||
@@ -203,14 +199,14 @@ function handleSelectionChange(selection: any) {
|
||||
function handleAdd() {
|
||||
state.dialog = {
|
||||
title: '添加字典',
|
||||
visible: true,
|
||||
visible: true
|
||||
};
|
||||
}
|
||||
|
||||
function handleUpdate(row: any) {
|
||||
state.dialog = {
|
||||
title: '修改字典',
|
||||
visible: true,
|
||||
visible: true
|
||||
};
|
||||
const id = row.id || state.ids;
|
||||
getDictFormData(id).then(({ data }) => {
|
||||
@@ -249,7 +245,7 @@ function handleDelete(row: any) {
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
deleteDictTypes(ids).then(() => {
|
||||
|
||||
@@ -233,11 +233,7 @@ import { ElForm, ElMessage, ElMessageBox, ElPopover } from 'element-plus';
|
||||
|
||||
import { Dialog, Option } from '@/types/common';
|
||||
|
||||
import {
|
||||
MenuFormData,
|
||||
MenuItem,
|
||||
MenuQueryParam
|
||||
} from '@/types/api/system/menu';
|
||||
import { MenuFormData, MenuItem, MenuQueryParam } from '@/types/api/menu';
|
||||
// API 依赖
|
||||
import {
|
||||
listMenus,
|
||||
@@ -246,7 +242,7 @@ import {
|
||||
addMenu,
|
||||
deleteMenus,
|
||||
updateMenu
|
||||
} from '@/api/system/menu';
|
||||
} from '@/api/menu';
|
||||
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import IconSelect from '@/components/IconSelect/index.vue';
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
reactive,
|
||||
ref,
|
||||
getCurrentInstance,
|
||||
toRefs,
|
||||
toRefs
|
||||
} from 'vue';
|
||||
|
||||
import {
|
||||
@@ -13,19 +13,15 @@ import {
|
||||
getPermFormDetail,
|
||||
addPerm,
|
||||
updatePerm,
|
||||
deletePerms,
|
||||
} from '@/api/system/perm';
|
||||
deletePerms
|
||||
} from '@/api/perm';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
|
||||
import { ElForm, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Dialog, Option } from '@/types/common';
|
||||
|
||||
import {
|
||||
PermFormData,
|
||||
PermItem,
|
||||
PermQueryParam,
|
||||
} from '@/types/api/system/perm';
|
||||
import { MenuItem } from '@/types/api/system/menu';
|
||||
import { PermFormData, PermItem, PermQueryParam } from '@/types/api/perm';
|
||||
import { MenuItem } from '@/types/api/menu';
|
||||
|
||||
const { proxy }: any = getCurrentInstance();
|
||||
|
||||
@@ -37,19 +33,19 @@ const props = defineProps({
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {} as MenuItem;
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.menu,
|
||||
(value) => {
|
||||
value => {
|
||||
queryParams.value.menuId = value.id;
|
||||
console.log('menu', value);
|
||||
handleQuery();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
deep: true
|
||||
}
|
||||
);
|
||||
|
||||
@@ -63,26 +59,26 @@ const state = reactive({
|
||||
multiple: true,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 10
|
||||
} as PermQueryParam,
|
||||
permList: [] as PermItem[],
|
||||
total: 0,
|
||||
dialog: {
|
||||
visible: false,
|
||||
visible: false
|
||||
} as Dialog,
|
||||
formData: {} as PermFormData,
|
||||
rules: {
|
||||
name: [{ required: true, message: '请输入权限名称', trigger: 'blur' }],
|
||||
perm: [{ required: true, message: '请输入权限标识', trigger: 'blur' }],
|
||||
method: [{ required: true, message: '请选择请求方式', trigger: 'blur' }],
|
||||
method: [{ required: true, message: '请选择请求方式', trigger: 'blur' }]
|
||||
},
|
||||
microServiceOptions: [] as Option[],
|
||||
requestMethodOptions: [] as Option[],
|
||||
urlPerm: {
|
||||
requestMethod: '',
|
||||
serviceName: '',
|
||||
requestPath: '',
|
||||
},
|
||||
requestPath: ''
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
@@ -96,7 +92,7 @@ const {
|
||||
microServiceOptions,
|
||||
requestMethodOptions,
|
||||
urlPerm,
|
||||
queryParams,
|
||||
queryParams
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
@@ -143,7 +139,7 @@ function handleAdd() {
|
||||
loadDictOptions();
|
||||
state.dialog = {
|
||||
title: '添加权限',
|
||||
visible: true,
|
||||
visible: true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -151,14 +147,14 @@ function handleUpdate(row: any) {
|
||||
loadDictOptions();
|
||||
state.dialog = {
|
||||
title: '修改权限',
|
||||
visible: true,
|
||||
visible: true
|
||||
};
|
||||
const id = row.id || state.ids;
|
||||
getPermFormDetail(id).then((response) => {
|
||||
getPermFormDetail(id).then(response => {
|
||||
const { data } = response;
|
||||
state.formData = data;
|
||||
if (data && data.urlPerm) {
|
||||
// GET:/youlai-admin/api/v1/users
|
||||
// GET:/youlai-system/api/v1/users
|
||||
const urlPermArr = data.urlPerm.split(':');
|
||||
state.urlPerm.requestMethod = urlPermArr[0];
|
||||
state.urlPerm.serviceName = urlPermArr[1].substring(
|
||||
@@ -225,7 +221,7 @@ function resetForm() {
|
||||
state.urlPerm = {
|
||||
requestMethod: '',
|
||||
serviceName: '',
|
||||
requestPath: '',
|
||||
requestPath: ''
|
||||
};
|
||||
}
|
||||
|
||||
@@ -239,7 +235,7 @@ function handleDelete(row: any) {
|
||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
deletePerms(ids).then(() => {
|
||||
|
||||
@@ -36,9 +36,9 @@ import PermTable from './components/Perm.vue';
|
||||
|
||||
import { reactive, toRefs } from 'vue';
|
||||
import { WarningFilled } from '@element-plus/icons-vue';
|
||||
import { MenuItem } from '@/types/api/system/menu';
|
||||
import { MenuItem } from '@/types/api/menu';
|
||||
const state = reactive({
|
||||
menu: {} as MenuItem,
|
||||
menu: {} as MenuItem
|
||||
});
|
||||
|
||||
const { menu } = toRefs(state);
|
||||
|
||||
@@ -14,17 +14,13 @@ import {
|
||||
deleteRoles,
|
||||
getRoleResources,
|
||||
updateRoleResource
|
||||
} from '@/api/system/role';
|
||||
import { listResources } from '@/api/system/menu';
|
||||
} from '@/api/role';
|
||||
import { listResources } from '@/api/menu';
|
||||
|
||||
import { ElForm, ElMessage, ElMessageBox, ElTree } from 'element-plus';
|
||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||
import {
|
||||
RoleFormData,
|
||||
RoleItem,
|
||||
RoleQueryParam
|
||||
} from '@/types/api/system/role';
|
||||
import { Resource } from '@/types/api/system/menu';
|
||||
import { RoleFormData, RoleItem, RoleQueryParam } from '@/types/api/role';
|
||||
import { Resource } from '@/types/api/menu';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
|
||||
const emit = defineEmits(['roleClick']);
|
||||
|
||||
@@ -27,9 +27,9 @@ import {
|
||||
downloadTemplate,
|
||||
exportUser,
|
||||
importUser
|
||||
} from '@/api/system/user';
|
||||
import { listDeptOptions } from '@/api/system/dept';
|
||||
import { listRoleOptions } from '@/api/system/role';
|
||||
} from '@/api/user';
|
||||
import { listDeptOptions } from '@/api/dept';
|
||||
import { listRoleOptions } from '@/api/role';
|
||||
|
||||
// 组件依赖
|
||||
import {
|
||||
@@ -55,7 +55,7 @@ import {
|
||||
UserQueryParam,
|
||||
UserFormData,
|
||||
UserImportFormData
|
||||
} from '@/types/api/system/user';
|
||||
} from '@/types/api/user';
|
||||
|
||||
import { Option, Dialog } from '@/types/common';
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'member',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted, toRefs } from 'vue';
|
||||
import { ElTable } from 'element-plus';
|
||||
import { Search, Refresh } from '@element-plus/icons-vue';
|
||||
|
||||
import { listMemebersPage } from '@/api/ums/member';
|
||||
import { MemberQueryParam, MemberItem } from '@/types/api/ums/member';
|
||||
|
||||
const state = reactive({
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
} as MemberQueryParam,
|
||||
memberList: [] as MemberItem[],
|
||||
});
|
||||
|
||||
const { loading, queryParams, memberList, total } = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listMemebersPage(state.queryParams).then(({ data }) => {
|
||||
state.memberList = data.list;
|
||||
state.total = data.total;
|
||||
state.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
state.queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
nickName: '',
|
||||
};
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection: any) {
|
||||
state.ids = selection.map((item: { id: any }) => item.id);
|
||||
state.single = selection.length != 1;
|
||||
state.multiple = !selection.length;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="queryParams.nickName"
|
||||
placeholder="会员昵称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button :icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="memberList"
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" align="center" />
|
||||
<el-table-column type="expand" width="120" label="会员地址">
|
||||
<template #default="scope">
|
||||
<el-table :data="scope.row.addressList" size="small" border>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column align="center" label="收货人" prop="name" />
|
||||
<el-table-column align="center" label="联系方式" prop="mobile" />
|
||||
<el-table-column align="center" label="收货地址">
|
||||
<template #default="scope">
|
||||
{{
|
||||
scope.row.province +
|
||||
scope.row.city +
|
||||
scope.row.area +
|
||||
scope.row.address
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="邮编" prop="zipCode" />
|
||||
<el-table-column align="center" label="是否默认">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.defaulted == 1" type="success"
|
||||
>是</el-tag
|
||||
>
|
||||
<el-tag v-if="scope.row.defaulted == 0" type="info">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column type="index" label="序号" width="100" align="center" />
|
||||
<el-table-column prop="nickName" label="昵称" />
|
||||
<el-table-column label="性别" width="80">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.gender === 0">未知</span>
|
||||
<span v-if="scope.row.gender === 1">男</span>
|
||||
<span v-if="scope.row.gender === 2">女</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="头像" width="100">
|
||||
<template #default="scope">
|
||||
<el-popover placement="right" :width="400" trigger="hover">
|
||||
<img :src="scope.row.avatarUrl" width="400" height="400" />
|
||||
<template #reference>
|
||||
<img
|
||||
:src="scope.row.avatarUrl"
|
||||
style="max-height: 60px; max-width: 60px"
|
||||
/>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="mobile" label="手机号码" />
|
||||
<el-table-column prop="birthday" label="出生日期" />
|
||||
<el-table-column prop="status" width="80" label="状态">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status === 1" type="success">正常</el-tag>
|
||||
<el-tag v-else type="info">禁用</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="createTime" label="注册时间" />
|
||||
|
||||
<el-table-column label="账户余额">
|
||||
<template #default="scope">
|
||||
{{ scope.row.balance / 100 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页工具条 -->
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user