feat: 同步接口更新
Former-commit-id: 29a22a96043a55445d48a086aa0a9157bcf7d6c6
This commit is contained in:
@@ -1,36 +0,0 @@
|
|||||||
import { SeataFormData } from '@/types/api/lab/seata';
|
|
||||||
import request from '@/utils/request';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单支付
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function payOrder(data: SeataFormData) {
|
|
||||||
return request({
|
|
||||||
url: '/youlai-lab/api/v1/seata/order/_pay',
|
|
||||||
method: 'post',
|
|
||||||
data: data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Seata模拟数据(包括订单信息、商品信息、会员余额信息)
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function getSeataData() {
|
|
||||||
return request({
|
|
||||||
url: '/youlai-lab/api/v1/seata/data',
|
|
||||||
method: 'get',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重置Seata模拟数据
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function resetSeataData() {
|
|
||||||
return request({
|
|
||||||
url: '/youlai-lab/api/v1/seata/data/_reset',
|
|
||||||
method: 'put',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,7 @@ export function listCategories(queryParams: object) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories',
|
url: '/mall-pms/api/v1/categories',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: queryParams
|
params: queryParams,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ export function listCategories(queryParams: object) {
|
|||||||
export function listCategoryOptions(): AxiosPromise<Option[]> {
|
export function listCategoryOptions(): AxiosPromise<Option[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories/options',
|
url: '/mall-pms/api/v1/categories/options',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export function listCategoryOptions(): AxiosPromise<Option[]> {
|
|||||||
export function getCategoryDetail(id: number) {
|
export function getCategoryDetail(id: number) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories/' + id,
|
url: '/mall-pms/api/v1/categories/' + id,
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ export function addCategory(data: object) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories',
|
url: '/mall-pms/api/v1/categories',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export function updateCategory(id: number, data: object) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories/' + id,
|
url: '/mall-pms/api/v1/categories/' + id,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ export function updateCategory(id: number, data: object) {
|
|||||||
export function deleteCategories(ids: string) {
|
export function deleteCategories(ids: string) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories/' + ids,
|
url: '/mall-pms/api/v1/categories/' + ids,
|
||||||
method: 'delete'
|
method: 'delete',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +88,6 @@ export function updateCategoryPart(id: number, data: object) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-pms/api/v1/categories/' + id,
|
url: '/mall-pms/api/v1/categories/' + id,
|
||||||
method: 'patch',
|
method: 'patch',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
CouponQueryParam,
|
CouponQueryParam,
|
||||||
CouponPageResult,
|
CouponPageResult,
|
||||||
CouponFormData
|
CouponFormData,
|
||||||
} from '@/types/api/sms/coupon';
|
} from '@/types/api/sms/coupon';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
@@ -17,7 +17,7 @@ export function lisCouponPages(
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-sms/api/v1/coupons/pages',
|
url: '/mall-sms/api/v1/coupons/pages',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: queryParams
|
params: queryParams,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ export function lisCouponPages(
|
|||||||
export function getCouponFormData(id: number): AxiosPromise<CouponFormData> {
|
export function getCouponFormData(id: number): AxiosPromise<CouponFormData> {
|
||||||
return request({
|
return request({
|
||||||
url: '/mall-sms/api/v1/coupons/' + id + '/form_data',
|
url: '/mall-sms/api/v1/coupons/' + id + '/form_data',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ export function addCoupon(data: CouponFormData) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-sms/api/v1/coupons',
|
url: '/mall-sms/api/v1/coupons',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ export function updateCoupon(id: number, data: CouponFormData) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/mall-sms/api/v1/coupons/' + id,
|
url: '/mall-sms/api/v1/coupons/' + id,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +68,6 @@ export function updateCoupon(id: number, data: CouponFormData) {
|
|||||||
export function deleteCoupons(ids: string) {
|
export function deleteCoupons(ids: string) {
|
||||||
return request({
|
return request({
|
||||||
url: '/mall-sms/api/v1/coupons/' + ids,
|
url: '/mall-sms/api/v1/coupons/' + ids,
|
||||||
method: 'delete'
|
method: 'delete',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
MenuFormData,
|
MenuFormData,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
MenuQueryParam,
|
MenuQueryParam,
|
||||||
|
Resource,
|
||||||
} from '@/types/api/system/menu';
|
} from '@/types/api/system/menu';
|
||||||
import { Option } from '@/types/common';
|
import { Option } from '@/types/common';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
@@ -43,9 +44,9 @@ export function listMenuOptions(): AxiosPromise<Option[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取菜单权限树形列表
|
* 获取资源(菜单+权限)树形列表
|
||||||
*/
|
*/
|
||||||
export function getResource(): AxiosPromise<any> {
|
export function listResources(): AxiosPromise<Resource[]> {
|
||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/menus/resources',
|
url: '/youlai-admin/api/v1/menus/resources',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -56,7 +57,7 @@ export function getResource(): AxiosPromise<any> {
|
|||||||
* 获取菜单详情
|
* 获取菜单详情
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
export function getMenuDetail(id: number): AxiosPromise<MenuFormData> {
|
export function getMenuDetail(id: string): AxiosPromise<MenuFormData> {
|
||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/menus/' + id,
|
url: '/youlai-admin/api/v1/menus/' + id,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
RoleFormData,
|
RoleFormData,
|
||||||
RolePageResult,
|
RolePageResult,
|
||||||
RoleQueryParam,
|
RoleQueryParam,
|
||||||
RoleResourceData
|
RoleResource,
|
||||||
} from '@/types/api/system/role';
|
} from '@/types/api/system/role';
|
||||||
|
|
||||||
import { Option } from '@/types/common';
|
import { Option } from '@/types/common';
|
||||||
@@ -20,7 +20,7 @@ export function listRolePages(
|
|||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/pages',
|
url: '/youlai-admin/api/v1/roles/pages',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: queryParams
|
params: queryParams,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export function listRoleOptions(
|
|||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/options',
|
url: '/youlai-admin/api/v1/roles/options',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: queryParams
|
params: queryParams,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,10 +44,10 @@ export function listRoleOptions(
|
|||||||
*
|
*
|
||||||
* @param queryParams
|
* @param queryParams
|
||||||
*/
|
*/
|
||||||
export function getRoleResourceIds(roleId: string): AxiosPromise<any> {
|
export function getRoleResources(roleId: string): AxiosPromise<RoleResource> {
|
||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/' + roleId + '/resources',
|
url: '/youlai-admin/api/v1/roles/' + roleId + '/resources',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,12 +58,12 @@ export function getRoleResourceIds(roleId: string): AxiosPromise<any> {
|
|||||||
*/
|
*/
|
||||||
export function updateRoleResource(
|
export function updateRoleResource(
|
||||||
roleId: string,
|
roleId: string,
|
||||||
data: RoleResourceData
|
data: RoleResource
|
||||||
): AxiosPromise<any> {
|
): AxiosPromise<any> {
|
||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/' + roleId + '/resources',
|
url: '/youlai-admin/api/v1/roles/' + roleId + '/resources',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ export function updateRoleResource(
|
|||||||
export function getRoleFormDetail(id: number): AxiosPromise<RoleFormData> {
|
export function getRoleFormDetail(id: number): AxiosPromise<RoleFormData> {
|
||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/' + id,
|
url: '/youlai-admin/api/v1/roles/' + id,
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ export function addRole(data: RoleFormData) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles',
|
url: '/youlai-admin/api/v1/roles',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ export function updateRole(id: number, data: RoleFormData) {
|
|||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/' + id,
|
url: '/youlai-admin/api/v1/roles/' + id,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data
|
data: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +114,6 @@ export function updateRole(id: number, data: RoleFormData) {
|
|||||||
export function deleteRoles(ids: string) {
|
export function deleteRoles(ids: string) {
|
||||||
return request({
|
return request({
|
||||||
url: '/youlai-admin/api/v1/roles/' + ids,
|
url: '/youlai-admin/api/v1/roles/' + ids,
|
||||||
method: 'delete'
|
method: 'delete',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export const getLanguage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
|
legacy: false,
|
||||||
locale: getLanguage(),
|
locale: getLanguage(),
|
||||||
messages: messages
|
messages: messages
|
||||||
});
|
});
|
||||||
|
|||||||
9
src/types/api/lab/seata.d.ts
vendored
9
src/types/api/lab/seata.d.ts
vendored
@@ -1,9 +0,0 @@
|
|||||||
/**
|
|
||||||
* Seata表单类型声明
|
|
||||||
*/
|
|
||||||
export interface SeataFormData {
|
|
||||||
openTx: boolean;
|
|
||||||
stockEx: boolean;
|
|
||||||
accountEx: boolean;
|
|
||||||
orderEx: boolean;
|
|
||||||
}
|
|
||||||
39
src/types/api/system/menu.d.ts
vendored
39
src/types/api/system/menu.d.ts
vendored
@@ -10,8 +10,9 @@ export interface MenuQueryParam {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export interface MenuItem {
|
export interface MenuItem {
|
||||||
id: number;
|
id?: number;
|
||||||
parentId: number;
|
parentId: number;
|
||||||
|
type?: string | 'CATEGORY' | 'MENU' | 'EXTLINK';
|
||||||
createTime: string;
|
createTime: string;
|
||||||
updateTime: string;
|
updateTime: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -65,3 +66,39 @@ export interface MenuFormData {
|
|||||||
*/
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源(菜单+权限)类型
|
||||||
|
*/
|
||||||
|
export interface Resource {
|
||||||
|
/**
|
||||||
|
* 菜单值
|
||||||
|
*/
|
||||||
|
value: string;
|
||||||
|
/**
|
||||||
|
* 菜单文本
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
/**
|
||||||
|
* 子菜单
|
||||||
|
*/
|
||||||
|
children: Resource[];
|
||||||
|
/**
|
||||||
|
* 权限集合
|
||||||
|
*/
|
||||||
|
perms: Permission[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限类型
|
||||||
|
*/
|
||||||
|
export interface Permission {
|
||||||
|
/**
|
||||||
|
* 权限值
|
||||||
|
*/
|
||||||
|
value: string;
|
||||||
|
/**
|
||||||
|
* 权限文本
|
||||||
|
*/
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|||||||
3
src/types/api/system/role.d.ts
vendored
3
src/types/api/system/role.d.ts
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
import { StringMap } from 'i18next';
|
||||||
import { PageQueryParam, PageResult } from '../base';
|
import { PageQueryParam, PageResult } from '../base';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +41,7 @@ export interface RoleFormData {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export interface RoleResourceData {
|
export interface RoleResource {
|
||||||
menuIds: string[];
|
menuIds: string[];
|
||||||
permIds: string[];
|
permIds: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,376 +0,0 @@
|
|||||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'seata',
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { reactive, onMounted, toRefs } from 'vue';
|
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
|
||||||
import {
|
|
||||||
Money,
|
|
||||||
Refresh,
|
|
||||||
RefreshLeft,
|
|
||||||
Right,
|
|
||||||
CircleCheckFilled,
|
|
||||||
CircleCloseFilled,
|
|
||||||
} from '@element-plus/icons-vue';
|
|
||||||
import { payOrder, getSeataData, resetSeataData } from '@/api/lab/seata';
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import { SeataFormData } from '@/types/api/lab/seata';
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
// 保留改变前数据
|
|
||||||
cacheSeataData: {
|
|
||||||
status: undefined,
|
|
||||||
stockNum: undefined,
|
|
||||||
balance: undefined,
|
|
||||||
},
|
|
||||||
seataData: {
|
|
||||||
orderInfo: {
|
|
||||||
orderSn: undefined,
|
|
||||||
status: undefined,
|
|
||||||
},
|
|
||||||
stockInfo: {
|
|
||||||
name: undefined,
|
|
||||||
picUrl: undefined,
|
|
||||||
stockNum: undefined,
|
|
||||||
},
|
|
||||||
accountInfo: {
|
|
||||||
nickName: undefined,
|
|
||||||
avatarUrl: undefined,
|
|
||||||
balance: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
loading: false,
|
|
||||||
|
|
||||||
submitData: {
|
|
||||||
openTx: true, // 是否开启事务
|
|
||||||
orderEx: true, // 订单修改异常
|
|
||||||
} as SeataFormData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { cacheSeataData, seataData, loading, submitData } = toRefs(state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单支付(模拟)
|
|
||||||
*/
|
|
||||||
function handleOrderPay() {
|
|
||||||
// 数据校验
|
|
||||||
if (
|
|
||||||
(seataData.value.stockInfo.stockNum &&
|
|
||||||
seataData.value.stockInfo.stockNum != 999) ||
|
|
||||||
(seataData.value.accountInfo.balance &&
|
|
||||||
seataData.value.accountInfo.balance != 1000000000) ||
|
|
||||||
(seataData.value.orderInfo.status &&
|
|
||||||
seataData.value.orderInfo.status != 101)
|
|
||||||
) {
|
|
||||||
ElMessageBox.confirm(
|
|
||||||
'检查到当前数据已被污染,请先重置数据后尝试提交?',
|
|
||||||
'警告',
|
|
||||||
{
|
|
||||||
confirmButtonText: '重置数据',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
handleDataReset();
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
} else {
|
|
||||||
// 订单支付模拟提交
|
|
||||||
|
|
||||||
loading.value = true;
|
|
||||||
payOrder(submitData.value)
|
|
||||||
.then(() => {
|
|
||||||
ElMessage.success('订单支付成功');
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
cacheSeataData.value = {
|
|
||||||
status: seataData.value.orderInfo.status,
|
|
||||||
stockNum: seataData.value.stockInfo.stockNum,
|
|
||||||
balance: seataData.value.accountInfo.balance,
|
|
||||||
};
|
|
||||||
loadData();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载数据
|
|
||||||
*/
|
|
||||||
function loadData() {
|
|
||||||
loading.value = true;
|
|
||||||
getSeataData().then((response: any) => {
|
|
||||||
seataData.value = response.data;
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新数据
|
|
||||||
*/
|
|
||||||
function handleDataRefresh() {
|
|
||||||
loading.value = true;
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据重置
|
|
||||||
*/
|
|
||||||
function handleDataReset() {
|
|
||||||
loading.value = true;
|
|
||||||
resetSeataData().then(() => {
|
|
||||||
ElMessage.success('数据还原成功');
|
|
||||||
loading.value = false;
|
|
||||||
cacheSeataData.value = {
|
|
||||||
status: undefined,
|
|
||||||
stockNum: undefined,
|
|
||||||
balance: undefined,
|
|
||||||
};
|
|
||||||
loadData();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 第一次加载重置数据测试
|
|
||||||
handleDataReset();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="app-container">
|
|
||||||
<el-alert type="info">
|
|
||||||
<p style="font-size: 16px">
|
|
||||||
<b>模拟订单支付流程:</b>
|
|
||||||
扣减商品库存 → 扣减会员余额 → 修改订单状态
|
|
||||||
</p>
|
|
||||||
<p style="font-size: 14px">
|
|
||||||
<b> 分布式事务生效判断:</b>
|
|
||||||
<el-link :icon="CircleCheckFilled" type="success">全部成功</el-link>
|
|
||||||
或
|
|
||||||
<el-link type="danger" :icon="CircleCloseFilled">全部失败</el-link>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p style="font-size: 14px">
|
|
||||||
<b> 博客教程:</b>
|
|
||||||
<el-link
|
|
||||||
type="primary"
|
|
||||||
href="https://www.cnblogs.com/haoxianrui/"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
https://www.cnblogs.com/haoxianrui</el-link
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</el-alert>
|
|
||||||
|
|
||||||
<el-card class="box-card" shadow="always" style="margin-top: 20px">
|
|
||||||
<el-form :inline="true">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-form-item>
|
|
||||||
<el-switch
|
|
||||||
v-model="submitData.openTx"
|
|
||||||
active-value=""
|
|
||||||
active-text="开启事务"
|
|
||||||
inactive-text="关闭事务"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" :icon="Money" @click="handleOrderPay"
|
|
||||||
>订单支付</el-button
|
|
||||||
>
|
|
||||||
<el-button :icon="Refresh" @click="handleDataRefresh"
|
|
||||||
>刷新数据</el-button
|
|
||||||
>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="4" style="text-align: right">
|
|
||||||
<el-button :icon="RefreshLeft" @click="handleDataReset"
|
|
||||||
>重置数据</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<el-row :gutter="10" style="margin-top: 20px" v-loading="loading">
|
|
||||||
<el-col :span="8" :xs="24" class="card-panel__col">
|
|
||||||
<el-card class="box-card" shadow="always">
|
|
||||||
<template #header>
|
|
||||||
<svg-icon icon-class="goods" />
|
|
||||||
商品信息
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div style="display: flex">
|
|
||||||
<el-image
|
|
||||||
style="width: 100px; height: 100px"
|
|
||||||
:src="seataData.stockInfo.picUrl"
|
|
||||||
fit="fill"
|
|
||||||
/>
|
|
||||||
<div style="margin-left: 10px">
|
|
||||||
<el-form-item label="商品名称:">
|
|
||||||
{{ seataData.stockInfo.name }}
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="库存数量:" style="display: flex">
|
|
||||||
<div v-if="cacheSeataData.stockNum != null">
|
|
||||||
{{ cacheSeataData.stockNum }} 部
|
|
||||||
<el-icon>
|
|
||||||
<right />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ seataData.stockInfo.stockNum }} 部
|
|
||||||
|
|
||||||
<div v-if="cacheSeataData.stockNum" style="margin-left: 50px">
|
|
||||||
<el-link
|
|
||||||
v-if="
|
|
||||||
cacheSeataData.stockNum != seataData.stockInfo.stockNum
|
|
||||||
"
|
|
||||||
type="success"
|
|
||||||
:underline="false"
|
|
||||||
:icon="CircleCheckFilled"
|
|
||||||
>
|
|
||||||
修改成功
|
|
||||||
</el-link>
|
|
||||||
<el-link
|
|
||||||
v-else-if="
|
|
||||||
cacheSeataData.stockNum == seataData.stockInfo.stockNum
|
|
||||||
"
|
|
||||||
type="danger"
|
|
||||||
:underline="false"
|
|
||||||
:icon="CircleCloseFilled"
|
|
||||||
>
|
|
||||||
修改失败
|
|
||||||
</el-link>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="8" :xs="24" class="card-panel__col">
|
|
||||||
<el-card class="box-card" shadow="always">
|
|
||||||
<template #header>
|
|
||||||
<svg-icon icon-class="user" />
|
|
||||||
会员信息
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div style="display: flex">
|
|
||||||
<el-image
|
|
||||||
style="width: 100px; height: 100px"
|
|
||||||
:src="seataData.accountInfo.avatarUrl"
|
|
||||||
fit="fill"
|
|
||||||
/>
|
|
||||||
<div style="margin-left: 10px">
|
|
||||||
<el-form-item label="会员昵称:">
|
|
||||||
{{ seataData.accountInfo.nickName }}
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="会员余额:">
|
|
||||||
<div v-if="cacheSeataData.balance != null">
|
|
||||||
{{ (cacheSeataData.balance as any) / 100 }} 元
|
|
||||||
<el-icon>
|
|
||||||
<right />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
{{ (seataData.accountInfo.balance as any) / 100 }} 元
|
|
||||||
|
|
||||||
<div v-if="cacheSeataData.balance" style="margin-left: 50px">
|
|
||||||
<el-link
|
|
||||||
v-if="
|
|
||||||
cacheSeataData.balance != seataData.accountInfo.balance
|
|
||||||
"
|
|
||||||
type="success"
|
|
||||||
:underline="false"
|
|
||||||
:icon="CircleCheckFilled"
|
|
||||||
>
|
|
||||||
修改成功
|
|
||||||
</el-link>
|
|
||||||
<el-link
|
|
||||||
v-else-if="
|
|
||||||
cacheSeataData.balance == seataData.accountInfo.balance
|
|
||||||
"
|
|
||||||
type="danger"
|
|
||||||
:underline="false"
|
|
||||||
:icon="CircleCloseFilled"
|
|
||||||
>
|
|
||||||
修改失败
|
|
||||||
</el-link>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="8" :xs="24" class="card-panel__col">
|
|
||||||
<el-card class="box-card" shadow="always">
|
|
||||||
<template #header>
|
|
||||||
<svg-icon icon-class="order" />
|
|
||||||
订单信息
|
|
||||||
<el-checkbox
|
|
||||||
v-model="submitData.orderEx"
|
|
||||||
:label="true"
|
|
||||||
style="float: right; color: #f56c6c"
|
|
||||||
>
|
|
||||||
搞点异常</el-checkbox
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<el-form-item label="订单编号:">
|
|
||||||
{{ seataData.orderInfo.orderSn }}
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="订单状态:">
|
|
||||||
<div v-if="cacheSeataData.status == 101">
|
|
||||||
<el-tag type="info"> 待支付 </el-tag>
|
|
||||||
<el-icon>
|
|
||||||
<right />
|
|
||||||
</el-icon>
|
|
||||||
</div>
|
|
||||||
<el-tag v-if="seataData.orderInfo.status == 101" type="info"
|
|
||||||
>待支付</el-tag
|
|
||||||
>
|
|
||||||
<el-tag v-else-if="seataData.orderInfo.status == 201" type="success"
|
|
||||||
>已支付</el-tag
|
|
||||||
>
|
|
||||||
|
|
||||||
<div v-if="cacheSeataData.balance" style="margin-left: 50px">
|
|
||||||
<el-link
|
|
||||||
v-if="cacheSeataData.status != seataData.orderInfo.status"
|
|
||||||
type="success"
|
|
||||||
:underline="false"
|
|
||||||
:icon="CircleCheckFilled"
|
|
||||||
>
|
|
||||||
修改成功
|
|
||||||
</el-link>
|
|
||||||
<el-link
|
|
||||||
v-else
|
|
||||||
type="danger"
|
|
||||||
:underline="false"
|
|
||||||
:icon="CircleCloseFilled"
|
|
||||||
>
|
|
||||||
修改失败
|
|
||||||
</el-link>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card-panel__col {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
|
|
||||||
.el-link {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,111 +1,3 @@
|
|||||||
<!-- 商品分类层级最多为三层,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>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import {
|
||||||
listCategories,
|
listCategories,
|
||||||
@@ -268,6 +160,114 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</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>
|
<style>
|
||||||
.component-container {
|
.component-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -280,13 +280,10 @@ onMounted(() => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
|
line-height: 40px0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-tree-node__content {
|
.el-tree-node__content {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-divider--horizontal {
|
|
||||||
margin: 30px 0 15px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -49,20 +49,20 @@ const emit = defineEmits(['next', 'update:modelValue']);
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const goodsInfo: any = computed({
|
const goodsInfo: any = computed({
|
||||||
get: () => props.modelValue,
|
get: () => props.modelValue,
|
||||||
set: value => {
|
set: (value) => {
|
||||||
emit('update:modelValue', value);
|
emit('update:modelValue', value);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
categoryOptions: [] as Option[],
|
categoryOptions: [] as Option[],
|
||||||
pathLabels: []
|
pathLabels: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const { categoryOptions, pathLabels } = toRefs(state);
|
const { categoryOptions, pathLabels } = toRefs(state);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'goods'
|
name: 'goods',
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
Edit,
|
Edit,
|
||||||
Refresh,
|
Refresh,
|
||||||
Delete,
|
Delete,
|
||||||
View
|
View,
|
||||||
} from '@element-plus/icons-vue';
|
} from '@element-plus/icons-vue';
|
||||||
import { listSpuPages, deleteSpu } from '@/api/pms/goods';
|
import { listSpuPages, deleteSpu } from '@/api/pms/goods';
|
||||||
import { listCategoryOptions } from '@/api/pms/category';
|
import { listCategoryOptions } from '@/api/pms/category';
|
||||||
@@ -39,12 +39,12 @@ const state = reactive({
|
|||||||
total: 0,
|
total: 0,
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10
|
pageSize: 10,
|
||||||
} as GoodsQueryParam,
|
} as GoodsQueryParam,
|
||||||
goodsList: [] as GoodsItem[],
|
goodsList: [] as GoodsItem[],
|
||||||
categoryOptions: [] as Option[],
|
categoryOptions: [] as Option[],
|
||||||
goodDetail: undefined,
|
goodDetail: undefined,
|
||||||
dialogVisible: false
|
dialogVisible: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -55,7 +55,7 @@ const {
|
|||||||
categoryOptions,
|
categoryOptions,
|
||||||
goodDetail,
|
goodDetail,
|
||||||
total,
|
total,
|
||||||
dialogVisible
|
dialogVisible,
|
||||||
} = toRefs(state);
|
} = toRefs(state);
|
||||||
|
|
||||||
function handleQuery() {
|
function handleQuery() {
|
||||||
@@ -72,7 +72,7 @@ function resetQuery() {
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
categoryId: undefined
|
categoryId: undefined,
|
||||||
};
|
};
|
||||||
handleQuery();
|
handleQuery();
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ function handleAdd() {
|
|||||||
function handleUpdate(row: any) {
|
function handleUpdate(row: any) {
|
||||||
router.push({
|
router.push({
|
||||||
path: 'goods-detail',
|
path: 'goods-detail',
|
||||||
query: { goodsId: row.id, categoryId: row.categoryId }
|
query: { goodsId: row.id, categoryId: row.categoryId },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ function handleDelete(row: any) {
|
|||||||
ElMessageBox.confirm('是否确认删除选中的数据项?', '警告', {
|
ElMessageBox.confirm('是否确认删除选中的数据项?', '警告', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return deleteSpu(ids);
|
return deleteSpu(ids);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'advert'
|
name: 'advert',
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -14,17 +14,17 @@ import {
|
|||||||
getAdvertFormDetail,
|
getAdvertFormDetail,
|
||||||
updateAdvert,
|
updateAdvert,
|
||||||
addAdvert,
|
addAdvert,
|
||||||
deleteAdverts
|
deleteAdverts,
|
||||||
} from '@/api/sms/advert';
|
} from '@/api/sms/advert';
|
||||||
import { Dialog } from '@/types/common';
|
import { Dialog } from '@/types/common';
|
||||||
import {
|
import {
|
||||||
AdvertFormData,
|
AdvertFormData,
|
||||||
AdvertItem,
|
AdvertItem,
|
||||||
AdvertQueryParam
|
AdvertQueryParam,
|
||||||
} from '@/types/api/sms/advert';
|
} from '@/types/api/sms/advert';
|
||||||
|
|
||||||
const queryFormRef = ref(ElForm);
|
const queryFormRef = ref(ElForm); // 属性名必须和元素的ref属性值一致
|
||||||
const dataFormRef = ref(ElForm);
|
const dataFormRef = ref(ElForm); // 属性名必须和元素的ref属性值一致
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -40,13 +40,13 @@ const state = reactive({
|
|||||||
dialog: { title: '', visible: false } as Dialog,
|
dialog: { title: '', visible: false } as Dialog,
|
||||||
formData: {
|
formData: {
|
||||||
status: 1,
|
status: 1,
|
||||||
sort: 100
|
sort: 100,
|
||||||
} as AdvertFormData,
|
} as AdvertFormData,
|
||||||
rules: {
|
rules: {
|
||||||
title: [{ required: true, message: '请输入广告名称', trigger: 'blur' }],
|
title: [{ required: true, message: '请输入广告名称', trigger: 'blur' }],
|
||||||
picUrl: [{ required: true, message: '请上传广告图片', trigger: 'blur' }]
|
picUrl: [{ required: true, message: '请上传广告图片', trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
validityPeriod: '' as any
|
validityPeriod: '' as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -58,7 +58,7 @@ const {
|
|||||||
dialog,
|
dialog,
|
||||||
formData,
|
formData,
|
||||||
rules,
|
rules,
|
||||||
validityPeriod
|
validityPeriod,
|
||||||
} = toRefs(state);
|
} = toRefs(state);
|
||||||
|
|
||||||
function handleQuery() {
|
function handleQuery() {
|
||||||
@@ -84,14 +84,14 @@ function handleSelectionChange(selection: any) {
|
|||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
state.dialog = {
|
state.dialog = {
|
||||||
title: '添加广告',
|
title: '添加广告',
|
||||||
visible: true
|
visible: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpdate(row: any) {
|
function handleUpdate(row: any) {
|
||||||
state.dialog = {
|
state.dialog = {
|
||||||
title: '修改广告',
|
title: '修改广告',
|
||||||
visible: true
|
visible: true,
|
||||||
};
|
};
|
||||||
const advertId = row.id || state.ids;
|
const advertId = row.id || state.ids;
|
||||||
getAdvertFormDetail(advertId).then(({ data }) => {
|
getAdvertFormDetail(advertId).then(({ data }) => {
|
||||||
@@ -138,7 +138,7 @@ function handleDelete(row: any) {
|
|||||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
deleteAdverts(ids).then(() => {
|
deleteAdverts(ids).then(() => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<!--优惠券-->
|
<!--优惠券-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'coupon'
|
name: 'coupon',
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
getCouponFormData,
|
getCouponFormData,
|
||||||
updateCoupon,
|
updateCoupon,
|
||||||
addCoupon,
|
addCoupon,
|
||||||
deleteCoupons
|
deleteCoupons,
|
||||||
} from '@/api/sms/coupon';
|
} from '@/api/sms/coupon';
|
||||||
|
|
||||||
import { listCategoryOptions } from '@/api/pms/category';
|
import { listCategoryOptions } from '@/api/pms/category';
|
||||||
@@ -23,7 +23,7 @@ import { Dialog, Option } from '@/types/common';
|
|||||||
import {
|
import {
|
||||||
CouponItem,
|
CouponItem,
|
||||||
CouponQueryParam,
|
CouponQueryParam,
|
||||||
CouponFormData
|
CouponFormData,
|
||||||
} from '@/types/api/sms/coupon';
|
} from '@/types/api/sms/coupon';
|
||||||
import { GoodsItem, GoodsQueryParam } from '@/types/api/pms/goods';
|
import { GoodsItem, GoodsQueryParam } from '@/types/api/pms/goods';
|
||||||
|
|
||||||
@@ -40,38 +40,38 @@ const state = reactive({
|
|||||||
couponList: [] as CouponItem[],
|
couponList: [] as CouponItem[],
|
||||||
total: 0,
|
total: 0,
|
||||||
dialog: {
|
dialog: {
|
||||||
visible: false
|
visible: false,
|
||||||
} as Dialog,
|
} as Dialog,
|
||||||
//指定商品分类选择Dialog
|
//指定商品分类选择Dialog
|
||||||
spuCategoryChooseDialog: {
|
spuCategoryChooseDialog: {
|
||||||
visible: false
|
visible: false,
|
||||||
} as Dialog,
|
} as Dialog,
|
||||||
// 指定商品选择ialog
|
// 指定商品选择ialog
|
||||||
spuChooseDialog: {
|
spuChooseDialog: {
|
||||||
visible: false
|
visible: false,
|
||||||
} as Dialog,
|
} as Dialog,
|
||||||
formData: {
|
formData: {
|
||||||
type: 1,
|
type: 1,
|
||||||
platform: 0,
|
platform: 0,
|
||||||
validityPeriodType: 1,
|
validityPeriodType: 1,
|
||||||
perLimit: 1,
|
perLimit: 1,
|
||||||
applicationScope: 0
|
applicationScope: 0,
|
||||||
} as CouponFormData,
|
} as CouponFormData,
|
||||||
rules: {
|
rules: {
|
||||||
type: [{ required: true, message: '请输入优惠券名称', trigger: 'blur' }],
|
type: [{ required: true, message: '请输入优惠券名称', trigger: 'blur' }],
|
||||||
name: [{ required: true, message: '请选择优惠券类型', trigger: 'blur' }]
|
name: [{ required: true, message: '请选择优惠券类型', trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
validityPeriod: '' as any,
|
validityPeriod: '' as any,
|
||||||
perLimitChecked: false,
|
perLimitChecked: false,
|
||||||
spuCategoryOptions: [] as Option[],
|
spuCategoryOptions: [] as Option[],
|
||||||
spuCategoryProps: {
|
spuCategoryProps: {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
emitPath: false
|
emitPath: false,
|
||||||
},
|
},
|
||||||
spuList: [] as GoodsItem[],
|
spuList: [] as GoodsItem[],
|
||||||
spuTotal: 0,
|
spuTotal: 0,
|
||||||
spuQueryParams: { pageNum: 1, pageSize: 10 } as GoodsQueryParam,
|
spuQueryParams: { pageNum: 1, pageSize: 10 } as GoodsQueryParam,
|
||||||
checkedSpuIds: []
|
checkedSpuIds: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -89,7 +89,7 @@ const {
|
|||||||
spuCategoryProps,
|
spuCategoryProps,
|
||||||
spuList,
|
spuList,
|
||||||
spuTotal,
|
spuTotal,
|
||||||
checkedSpuIds
|
checkedSpuIds,
|
||||||
} = toRefs(state);
|
} = toRefs(state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,7 +136,7 @@ async function loadSpuList() {
|
|||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
dialog.value = {
|
dialog.value = {
|
||||||
title: '新增优惠券',
|
title: '新增优惠券',
|
||||||
visible: true
|
visible: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
loadSpuCategoryOptions();
|
loadSpuCategoryOptions();
|
||||||
@@ -146,7 +146,7 @@ function handleAdd() {
|
|||||||
async function handleUpdate(row: any) {
|
async function handleUpdate(row: any) {
|
||||||
dialog.value = {
|
dialog.value = {
|
||||||
title: '编辑优惠券',
|
title: '编辑优惠券',
|
||||||
visible: true
|
visible: true,
|
||||||
};
|
};
|
||||||
const id = row.id;
|
const id = row.id;
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ function handleDelete(row: any) {
|
|||||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
deleteCoupons(ids).then(() => {
|
deleteCoupons(ids).then(() => {
|
||||||
@@ -492,7 +492,7 @@ onMounted(() => {
|
|||||||
:titles="['商品列表', '已选择商品']"
|
:titles="['商品列表', '已选择商品']"
|
||||||
:props="{
|
:props="{
|
||||||
key: 'id',
|
key: 'id',
|
||||||
label: 'name'
|
label: 'name',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #left-footer>
|
<template #left-footer>
|
||||||
|
|||||||
@@ -142,16 +142,12 @@ function submitForm() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetForm() {
|
function cancel() {
|
||||||
|
state.dialog.visible = false;
|
||||||
dataFormRef.value.resetFields();
|
dataFormRef.value.resetFields();
|
||||||
state.checkedAuthorizedGrantTypes = [];
|
state.checkedAuthorizedGrantTypes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
|
||||||
resetForm();
|
|
||||||
state.dialog.visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(row: any) {
|
function handleDelete(row: any) {
|
||||||
const clientIds = [row.clientId || ids].join(',');
|
const clientIds = [row.clientId || ids].join(',');
|
||||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||||
|
|||||||
@@ -192,8 +192,10 @@ function handleDelete(row: any) {
|
|||||||
* 取消/关闭弹窗
|
* 取消/关闭弹窗
|
||||||
**/
|
**/
|
||||||
function cancel() {
|
function cancel() {
|
||||||
|
dialog.value.visible = false;
|
||||||
|
formData.value.id = undefined;
|
||||||
dataFormRef.value.resetFields();
|
dataFormRef.value.resetFields();
|
||||||
state.dialog.visible = false;
|
dataFormRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -44,6 +44,16 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="菜单类型" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-if="scope.row.type === 'MENU'" type="success">菜单</el-tag>
|
||||||
|
<el-tag v-if="scope.row.type === 'CATALOG'" type="warning"
|
||||||
|
>目录</el-tag
|
||||||
|
>
|
||||||
|
<el-tag v-if="scope.row.type === 'EXTLINK'" type="info">外链</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="状态" align="center" width="100">
|
<el-table-column label="状态" align="center" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.visible === 1" type="success">显示</el-tag>
|
<el-tag v-if="scope.row.visible === 1" type="success">显示</el-tag>
|
||||||
@@ -261,7 +271,7 @@ const state = reactive({
|
|||||||
name: '',
|
name: '',
|
||||||
visible: 1,
|
visible: 1,
|
||||||
sort: 1,
|
sort: 1,
|
||||||
component: 'Layout',
|
component: undefined,
|
||||||
type: 'MENU',
|
type: 'MENU',
|
||||||
} as MenuFormData,
|
} as MenuFormData,
|
||||||
rules: {
|
rules: {
|
||||||
@@ -333,8 +343,12 @@ function handleRowClick(row: any) {
|
|||||||
emit('menuClick', row);
|
emit('menuClick', row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增菜单
|
||||||
|
* @param row
|
||||||
|
*/
|
||||||
async function handleAdd(row: any) {
|
async function handleAdd(row: any) {
|
||||||
state.formData.id = undefined;
|
formData.value.id = undefined;
|
||||||
await loadMenuData();
|
await loadMenuData();
|
||||||
state.dialog = {
|
state.dialog = {
|
||||||
title: '添加菜单',
|
title: '添加菜单',
|
||||||
@@ -342,7 +356,6 @@ async function handleAdd(row: any) {
|
|||||||
};
|
};
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
// 行点击新增
|
// 行点击新增
|
||||||
|
|
||||||
state.formData.parentId = row.id;
|
state.formData.parentId = row.id;
|
||||||
if (row.id == '0') {
|
if (row.id == '0') {
|
||||||
state.formData.type = 'CATALOG';
|
state.formData.type = 'CATALOG';
|
||||||
@@ -362,15 +375,15 @@ async function handleAdd(row: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改弹窗
|
* 编辑菜单
|
||||||
*/
|
*/
|
||||||
async function handleUpdate(row: any) {
|
async function handleUpdate(row: MenuFormData) {
|
||||||
await loadMenuData();
|
await loadMenuData();
|
||||||
state.dialog = {
|
state.dialog = {
|
||||||
title: '修改菜单',
|
title: '编辑菜单',
|
||||||
visible: true,
|
visible: true,
|
||||||
};
|
};
|
||||||
const id = row.id || state.ids;
|
const id = row.id as string;
|
||||||
getMenuDetail(id).then(({ data }) => {
|
getMenuDetail(id).then(({ data }) => {
|
||||||
state.formData = data;
|
state.formData = data;
|
||||||
cacheData.value.menuType = data.type;
|
cacheData.value.menuType = data.type;
|
||||||
@@ -379,10 +392,10 @@ async function handleUpdate(row: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 菜单类型change事件
|
* 菜单类型 change
|
||||||
*/
|
*/
|
||||||
function handleMenuTypeChange(val: any) {
|
function handleMenuTypeChange(menuType: any) {
|
||||||
if (val !== cacheData.value.menuType) {
|
if (menuType !== cacheData.value.menuType) {
|
||||||
formData.value.path = '';
|
formData.value.path = '';
|
||||||
} else {
|
} else {
|
||||||
formData.value.path = cacheData.value.menuPath;
|
formData.value.path = cacheData.value.menuPath;
|
||||||
@@ -412,6 +425,11 @@ function submitForm() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除菜单
|
||||||
|
*
|
||||||
|
* @param row
|
||||||
|
*/
|
||||||
function handleDelete(row: any) {
|
function handleDelete(row: any) {
|
||||||
const ids = [row.id || state.ids].join(',');
|
const ids = [row.id || state.ids].join(',');
|
||||||
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
PermItem,
|
PermItem,
|
||||||
PermQueryParam,
|
PermQueryParam,
|
||||||
} from '@/types/api/system/perm';
|
} from '@/types/api/system/perm';
|
||||||
|
import { MenuItem } from '@/types/api/system/menu';
|
||||||
|
|
||||||
const { proxy }: any = getCurrentInstance();
|
const { proxy }: any = getCurrentInstance();
|
||||||
|
|
||||||
@@ -32,19 +33,23 @@ const queryFormRef = ref(ElForm);
|
|||||||
const dataFormRef = ref(ElForm);
|
const dataFormRef = ref(ElForm);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
menuId: {
|
menu: {
|
||||||
type: String,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
return '';
|
return {} as MenuItem;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.menuId,
|
() => props.menu,
|
||||||
(value) => {
|
(value) => {
|
||||||
state.queryParams.menuId = value;
|
queryParams.value.menuId = value.id;
|
||||||
|
console.log('menu', value);
|
||||||
handleQuery();
|
handleQuery();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -193,7 +198,7 @@ function submitForm() {
|
|||||||
state.urlPerm.requestPath;
|
state.urlPerm.requestPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.formData.menuId = props.menuId;
|
formData.value.menuId = props.menu.id;
|
||||||
if (state.formData.id) {
|
if (state.formData.id) {
|
||||||
updatePerm(state.formData.id, state.formData).then(() => {
|
updatePerm(state.formData.id, state.formData).then(() => {
|
||||||
ElMessage.success('修改成功');
|
ElMessage.success('修改成功');
|
||||||
@@ -258,7 +263,7 @@ onMounted(() => {
|
|||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
:icon="Plus"
|
:icon="Plus"
|
||||||
:disabled="!menuId"
|
v-if="menu.id && menu.type == 'MENU'"
|
||||||
@click="handleAdd"
|
@click="handleAdd"
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
>
|
>
|
||||||
@@ -267,6 +272,7 @@ onMounted(() => {
|
|||||||
:icon="Delete"
|
:icon="Delete"
|
||||||
:disabled="multiple"
|
:disabled="multiple"
|
||||||
@click="handleDelete"
|
@click="handleDelete"
|
||||||
|
v-if="menu.id && menu.type == 'MENU'"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@@ -15,14 +15,14 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<svg-icon icon-class="perm" />
|
<svg-icon icon-class="perm" />
|
||||||
<span style="margin: 0 5px">权限列表</span>
|
<span style="margin: 0 5px">权限列表</span>
|
||||||
<el-tag type="success" v-if="menuId" size="small">{{
|
<el-tag type="success" v-if="menu.id" size="small">{{
|
||||||
menuName
|
menu.name
|
||||||
}}</el-tag>
|
}}</el-tag>
|
||||||
<el-tag type="warning" v-else size="small"
|
<el-link :underline="false" type="warning" v-else size="small"
|
||||||
>请点击左侧菜单列表选择</el-tag
|
><el-icon><WarningFilled /></el-icon>请选中左侧菜单</el-link
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
<perm-table :menuId="menuId" :menuName="menuName" />
|
<perm-table :menu="menu" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -35,21 +35,23 @@ import MenuTable from './components/Menu.vue';
|
|||||||
import PermTable from './components/Perm.vue';
|
import PermTable from './components/Perm.vue';
|
||||||
|
|
||||||
import { reactive, toRefs } from 'vue';
|
import { reactive, toRefs } from 'vue';
|
||||||
|
import { WarningFilled } from '@element-plus/icons-vue';
|
||||||
|
import { MenuItem } from '@/types/api/system/menu';
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
menuId: undefined,
|
menu: {} as MenuItem,
|
||||||
menuName: '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { menuId, menuName } = toRefs(state);
|
const { menu } = toRefs(state);
|
||||||
|
|
||||||
function handleMenuClick(menuRow: any) {
|
function handleMenuClick(menuRow: MenuItem) {
|
||||||
if (menuRow) {
|
if (menuRow) {
|
||||||
state.menuId = menuRow.id;
|
menu.value.id = menuRow.id;
|
||||||
state.menuName = menuRow.name;
|
menu.value.type = menuRow.type;
|
||||||
|
menu.value.name = menuRow.name;
|
||||||
} else {
|
} else {
|
||||||
state.menuId = undefined;
|
menu.value.id = undefined;
|
||||||
state.menuName = '';
|
menu.value.type = undefined;
|
||||||
|
menu.value.name = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive, ref, toRefs, nextTick } from 'vue';
|
import { nextTick, onMounted, reactive, ref, toRefs } from 'vue';
|
||||||
import {
|
import {
|
||||||
listRolePages,
|
listRolePages,
|
||||||
updateRole,
|
updateRole,
|
||||||
getRoleFormDetail,
|
getRoleFormDetail,
|
||||||
addRole,
|
addRole,
|
||||||
deleteRoles,
|
deleteRoles,
|
||||||
getRoleResourceIds,
|
getRoleResources,
|
||||||
updateRoleResource,
|
updateRoleResource,
|
||||||
} from '@/api/system/role';
|
} from '@/api/system/role';
|
||||||
import { getResource } from '@/api/system/menu';
|
import { listResources } from '@/api/system/menu';
|
||||||
|
|
||||||
import { ElForm, ElMessage, ElMessageBox, ElTree } from 'element-plus';
|
import { ElForm, ElMessage, ElMessageBox, ElTree } from 'element-plus';
|
||||||
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
import { Search, Plus, Edit, Refresh, Delete } from '@element-plus/icons-vue';
|
||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
RoleItem,
|
RoleItem,
|
||||||
RoleQueryParam,
|
RoleQueryParam,
|
||||||
} from '@/types/api/system/role';
|
} from '@/types/api/system/role';
|
||||||
|
import { Resource } from '@/types/api/system/menu';
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||||
|
|
||||||
const emit = defineEmits(['roleClick']);
|
const emit = defineEmits(['roleClick']);
|
||||||
@@ -55,8 +56,11 @@ const state = reactive({
|
|||||||
code: [{ required: true, message: '请输入角色编码', trigger: 'blur' }],
|
code: [{ required: true, message: '请输入角色编码', trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
resourceDialogVisible: false,
|
resourceDialogVisible: false,
|
||||||
menuOptions: [] as any[],
|
resourceOptions: [] as Resource[],
|
||||||
permOptions: [] as any[],
|
btnPerms: {} as any,
|
||||||
|
// 勾选的菜单ID
|
||||||
|
checkedMenuIds: new Set([]),
|
||||||
|
allPermIds: [] as string[],
|
||||||
checkedRole: {
|
checkedRole: {
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
@@ -73,9 +77,9 @@ const {
|
|||||||
formData,
|
formData,
|
||||||
rules,
|
rules,
|
||||||
resourceDialogVisible,
|
resourceDialogVisible,
|
||||||
menuOptions,
|
|
||||||
permOptions,
|
|
||||||
checkedRole,
|
checkedRole,
|
||||||
|
resourceOptions,
|
||||||
|
btnPerms,
|
||||||
} = toRefs(state);
|
} = toRefs(state);
|
||||||
|
|
||||||
function handleQuery() {
|
function handleQuery() {
|
||||||
@@ -87,7 +91,9 @@ function handleQuery() {
|
|||||||
state.loading = false;
|
state.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 查询重置
|
||||||
|
*/
|
||||||
function resetQuery() {
|
function resetQuery() {
|
||||||
queryFormRef.value.resetFields();
|
queryFormRef.value.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
@@ -148,8 +154,10 @@ function submitFormData() {
|
|||||||
* 取消
|
* 取消
|
||||||
*/
|
*/
|
||||||
function cancel() {
|
function cancel() {
|
||||||
state.dialog.visible = false;
|
dialog.value.visible = false;
|
||||||
|
formData.value.id = undefined;
|
||||||
dataFormRef.value.resetFields();
|
dataFormRef.value.resetFields();
|
||||||
|
dataFormRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,13 +179,26 @@ function handleDelete(row: any) {
|
|||||||
.catch(() => ElMessage.info('已取消删除'));
|
.catch(() => ElMessage.info('已取消删除'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleResourceCheckChange = (
|
||||||
|
data: Resource,
|
||||||
|
isCheck: boolean,
|
||||||
|
sonHasCheck: boolean
|
||||||
|
) => {
|
||||||
|
console.log('data', data);
|
||||||
|
console.log('isCheck', isCheck);
|
||||||
|
if (data.perms) {
|
||||||
|
data.perms.forEach((item) => {
|
||||||
|
btnPerms.value[item.value] = isCheck;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分配资源权限
|
* 分配资源(菜单+权限)弹窗
|
||||||
*/
|
*/
|
||||||
function handleResourceAssign(row: RoleItem) {
|
function openRoleResourceDialog(row: RoleItem) {
|
||||||
resourceDialogVisible.value = true;
|
resourceDialogVisible.value = true;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
permOptions.value.map((item) => (item.checked = false));
|
|
||||||
|
|
||||||
const roleId: any = row.id;
|
const roleId: any = row.id;
|
||||||
checkedRole.value = {
|
checkedRole.value = {
|
||||||
@@ -185,47 +206,72 @@ function handleResourceAssign(row: RoleItem) {
|
|||||||
name: row.name,
|
name: row.name,
|
||||||
};
|
};
|
||||||
|
|
||||||
//资源下拉数据
|
// 获取所有的资源
|
||||||
getResource().then((response) => {
|
listResources().then((response) => {
|
||||||
state.menuOptions = response.data.menus;
|
resourceOptions.value = response.data;
|
||||||
state.permOptions = response.data.perms;
|
|
||||||
|
|
||||||
// 获取角色拥有的资源数据进行勾选
|
// 获取角色拥有的资源
|
||||||
getRoleResourceIds(roleId).then((res) => {
|
getRoleResources(roleId).then(({ data }) => {
|
||||||
const checkedMenuIds = res.data.menuIds;
|
// 勾选的菜单回显
|
||||||
const checkedPermIds = res.data.permIds;
|
const checkedMenuIds = data.menuIds;
|
||||||
resourceRef.value.setCheckedKeys(checkedMenuIds);
|
resourceRef.value.setCheckedKeys(checkedMenuIds);
|
||||||
|
|
||||||
permOptions.value.forEach((perm) => {
|
nextTick(() => {
|
||||||
if (checkedPermIds.includes(perm.value)) {
|
// 勾选的权限回显
|
||||||
perm.checked = true;
|
const rolePermIds = data.permIds;
|
||||||
|
|
||||||
|
state.allPermIds = filterResourcePermIds(response.data, []);
|
||||||
|
if (state.allPermIds) {
|
||||||
|
state.allPermIds.forEach((permId) => {
|
||||||
|
if (rolePermIds.indexOf(permId) > -1) {
|
||||||
|
btnPerms.value[permId] = true;
|
||||||
} else {
|
} else {
|
||||||
perm.checked = false;
|
btnPerms.value[permId] = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterResourcePermIds = (resources: Resource[], permIds: string[]) => {
|
||||||
|
resources.forEach((resource) => {
|
||||||
|
if (resource.perms) {
|
||||||
|
resource.perms.forEach((perm) => {
|
||||||
|
permIds.push(perm.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (resource.children) {
|
||||||
|
filterResourcePermIds(resource.children, permIds);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return permIds;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* 分配资源权限提交
|
* 分配资源提交
|
||||||
*/
|
*/
|
||||||
function handleRoleResourceSubmit() {
|
function handleRoleResourceSubmit() {
|
||||||
const checkedMenuIds: any[] = resourceRef.value
|
const checkedMenuIds: any[] = resourceRef.value
|
||||||
.getCheckedNodes(false, true)
|
.getCheckedNodes(false, true)
|
||||||
.map((node: any) => node.value);
|
.map((node: any) => node.value);
|
||||||
|
|
||||||
const checkedPermIds = state.permOptions
|
const checkedPermIds = [] as string[];
|
||||||
.filter((item) => item.checked)
|
if (state.allPermIds) {
|
||||||
.map((item) => item.value);
|
state.allPermIds.forEach((permId) => {
|
||||||
|
if (btnPerms.value[permId]) {
|
||||||
|
checkedPermIds.push(permId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const roleResourceData = {
|
const RoleResource = {
|
||||||
menuIds: checkedMenuIds,
|
menuIds: checkedMenuIds,
|
||||||
permIds: checkedPermIds,
|
permIds: checkedPermIds,
|
||||||
};
|
};
|
||||||
|
|
||||||
updateRoleResource(checkedRole.value.id, roleResourceData).then((res) => {
|
updateRoleResource(checkedRole.value.id, RoleResource).then((res) => {
|
||||||
ElMessage.success('分配权限成功');
|
ElMessage.success('分配权限成功');
|
||||||
state.resourceDialogVisible = false;
|
state.resourceDialogVisible = false;
|
||||||
handleQuery();
|
handleQuery();
|
||||||
@@ -291,14 +337,16 @@ onMounted(() => {
|
|||||||
<el-table-column label="角色编码" prop="code" />
|
<el-table-column label="角色编码" prop="code" />
|
||||||
<el-table-column label="操作" align="center" width="200">
|
<el-table-column label="操作" align="center" width="200">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<el-tooltip content="分配资源" effect="light">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="success"
|
||||||
circle
|
circle
|
||||||
plain
|
plain
|
||||||
@click.stop="handleResourceAssign(scope.row)"
|
@click.stop="openRoleResourceDialog(scope.row)"
|
||||||
>
|
>
|
||||||
<svg-icon icon-class="perm" />
|
<svg-icon icon-class="perm" />
|
||||||
</el-button>
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -373,37 +421,38 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!--分配权限弹窗-->
|
<!--分配资源弹窗-->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:title="'【' + checkedRole.name + '】分配权限'"
|
:title="'角色【' + checkedRole.name + '】资源分配'"
|
||||||
v-model="resourceDialogVisible"
|
v-model="resourceDialogVisible"
|
||||||
width="1000px"
|
width="800px"
|
||||||
>
|
>
|
||||||
<el-scrollbar max-height="600px" v-loading="loading">
|
<el-scrollbar max-height="600px" v-loading="loading">
|
||||||
<el-tree
|
<el-tree
|
||||||
ref="resourceRef"
|
ref="resourceRef"
|
||||||
node-key="value"
|
node-key="value"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
:data="menuOptions"
|
:data="resourceOptions"
|
||||||
:default-expand-all="true"
|
:default-expand-all="true"
|
||||||
|
@check-change="handleResourceCheckChange"
|
||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ data }">
|
||||||
<div v-if="data.isPerm == true" class="resource-tree-node">
|
{{ data.label }}
|
||||||
<div class="resource-tree-node__content">
|
|
||||||
|
<div v-if="data.perms" class="resource-tree-node">
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<div class="node-content">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-for="perm in permOptions.filter(
|
v-for="perm in data.perms"
|
||||||
(perm) => perm.parentId == data.permPid
|
|
||||||
)"
|
|
||||||
:key="perm.value"
|
:key="perm.value"
|
||||||
:label="perm.value"
|
:label="perm.value"
|
||||||
v-model="perm.checked"
|
|
||||||
border
|
border
|
||||||
size="small"
|
size="small"
|
||||||
|
v-model="btnPerms[perm.value]"
|
||||||
>{{ perm.label }}</el-checkbox
|
>{{ perm.label }}</el-checkbox
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span v-else>{{ node.label }}</span>
|
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@@ -425,18 +474,16 @@ onMounted(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-right: 8px;
|
justify-content: flex-end;
|
||||||
margin-left: -28px !important;
|
margin: 0 50px;
|
||||||
|
.node-content {
|
||||||
&__content {
|
width: 400px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.el-checkbox--default {
|
.el-divider--vertical {
|
||||||
background-color: transparent !important;
|
height: 2em !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-tree-node__content {
|
.el-tree-node__content {
|
||||||
|
|||||||
@@ -348,9 +348,10 @@ function handleDelete(row: { [key: string]: any }) {
|
|||||||
* 取消
|
* 取消
|
||||||
*/
|
*/
|
||||||
function cancel() {
|
function cancel() {
|
||||||
state.dialog.visible = false;
|
dialog.value.visible = false;
|
||||||
state.formData.id = undefined;
|
formData.value.id = undefined;
|
||||||
dataFormRef.value.resetFields();
|
dataFormRef.value.resetFields();
|
||||||
|
dataFormRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user