refactor: keepalive无效问题修复和代码vue社区代码规范调整
Former-commit-id: f661982d54f1738ff9739f1afc993181a466f052
This commit is contained in:
316
src/views/lab/seata/index.vue
Normal file
316
src/views/lab/seata/index.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<!-- 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";
|
||||
|
||||
const state = reactive({
|
||||
// 保留改变前数据
|
||||
cacheSeataData: {
|
||||
status: undefined,
|
||||
stockNum: undefined,
|
||||
balance: undefined
|
||||
},
|
||||
seataData: {
|
||||
orderInfo: {
|
||||
orderSn: undefined,
|
||||
status: undefined
|
||||
},
|
||||
skuInfo: {
|
||||
name: undefined,
|
||||
picUrl: undefined,
|
||||
stockNum: undefined
|
||||
},
|
||||
memberInfo: {
|
||||
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.skuInfo.stockNum && seataData.value.skuInfo.stockNum != 999
|
||||
|| (seataData.value.memberInfo.balance && seataData.value.memberInfo.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.skuInfo.stockNum,
|
||||
balance: seataData.value.memberInfo.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.skuInfo.picUrl" fit="fill" />
|
||||
<div style="margin-left: 10px;">
|
||||
<el-form-item label="商品名称:">
|
||||
{{ seataData.skuInfo.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.skuInfo.stockNum }} 部
|
||||
|
||||
<div v-if="cacheSeataData.stockNum" style="margin-left: 50px;">
|
||||
<el-link v-if="cacheSeataData.stockNum != seataData.skuInfo.stockNum" type="success"
|
||||
:underline="false" :icon="CircleCheckFilled">
|
||||
修改成功
|
||||
</el-link>
|
||||
<el-link v-else-if="cacheSeataData.stockNum == seataData.skuInfo.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.memberInfo.avatarUrl"
|
||||
fit="fill" />
|
||||
<div style="margin-left: 10px;">
|
||||
<el-form-item label="会员昵称:">
|
||||
{{ seataData.memberInfo.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.memberInfo.balance as any) / 100 }} 元
|
||||
|
||||
<div v-if="cacheSeataData.balance" style="margin-left: 50px;">
|
||||
<el-link v-if="cacheSeataData.balance != seataData.memberInfo.balance"
|
||||
type="success" :underline="false" :icon="CircleCheckFilled">
|
||||
修改成功
|
||||
</el-link>
|
||||
<el-link v-else-if="cacheSeataData.balance == seataData.memberInfo.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,3 +1,122 @@
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<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 { Dialog, Order, OrderQueryParam } from "@/types";
|
||||
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: [],
|
||||
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">
|
||||
<!-- 搜索表单 -->
|
||||
@@ -116,118 +235,5 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from "vue";
|
||||
import { ElForm } from "element-plus";
|
||||
import { Dialog, Order, OrderQueryParam } from "@/types";
|
||||
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: [],
|
||||
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>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,76 +1,10 @@
|
||||
<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-show="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>
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "brand"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from "vue";
|
||||
@@ -220,5 +154,79 @@ onMounted(() => {
|
||||
});
|
||||
</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-show="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,34 +1,11 @@
|
||||
<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>
|
||||
<!-- 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';
|
||||
@@ -62,6 +39,35 @@ function handleCategoryClick(categoryRow: any) {
|
||||
}
|
||||
</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>
|
||||
|
||||
@@ -146,13 +146,13 @@ function handleNext() {
|
||||
.filter((item) => item.main == true && item.url)
|
||||
.map((item) => item.url);
|
||||
if (mainPicUrl && mainPicUrl.length > 0) {
|
||||
goodsInfo.picUrl = mainPicUrl[0];
|
||||
goodsInfo.value.picUrl = mainPicUrl[0];
|
||||
}
|
||||
const subPicUrl = state.pictures
|
||||
.filter((item) => item.main == false && item.url)
|
||||
.map((item) => item.url);
|
||||
if (subPicUrl && subPicUrl.length > 0) {
|
||||
goodsInfo.subPicUrls = subPicUrl;
|
||||
goodsInfo.value.subPicUrls = subPicUrl;
|
||||
}
|
||||
emit("next");
|
||||
}
|
||||
|
||||
@@ -203,7 +203,6 @@ watch(() => goodsInfo.value.categoryId, (newVal) => {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
|
||||
@@ -33,10 +33,10 @@ const state = reactive({
|
||||
loaded: false,
|
||||
active: 0,
|
||||
goodsInfo: {
|
||||
album: [] as string[],
|
||||
attrList: [] as any[],
|
||||
specList: [] as any[],
|
||||
skuList: [] as any[]
|
||||
album: [],
|
||||
attrList: [],
|
||||
specList: [],
|
||||
skuList: []
|
||||
} as GoodsDetail
|
||||
});
|
||||
|
||||
@@ -48,8 +48,8 @@ function loadData() {
|
||||
if (goodsId) {
|
||||
getGoodsDetail(goodsId).then((response) => {
|
||||
state.goodsInfo = response.data
|
||||
state.goodsInfo.originPrice = state.goodsInfo.originPrice / 100
|
||||
state.goodsInfo.price = state.goodsInfo.price / 100
|
||||
state.goodsInfo.originPrice = (state.goodsInfo.originPrice as any) / 100
|
||||
state.goodsInfo.price = (state.goodsInfo.price as any) / 100
|
||||
state.loaded = true
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -1,8 +1,129 @@
|
||||
<!-- 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 { listGoodsPages, deleteGoods } from "@/api/pms/goods";
|
||||
import { listCascadeCategories } from "@/api/pms/category";
|
||||
import { GoodsItem, GoodsQueryParam } from "@/types";
|
||||
import {moneyFormatter} from '@/utils/filter'
|
||||
|
||||
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: [],
|
||||
goodDetail: undefined,
|
||||
dialogVisible: false,
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
multiple,
|
||||
queryParams,
|
||||
goodsList,
|
||||
categoryOptions,
|
||||
goodDetail,
|
||||
total,
|
||||
dialogVisible,
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listGoodsPages(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 deleteGoods(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(() => {
|
||||
listCascadeCategories({}).then((response) => {
|
||||
state.categoryOptions = ref(response.data);
|
||||
});
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryForm" :inline="true">
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd"
|
||||
<el-button type="success" :icon="Position" @click="handleAdd"
|
||||
>发布商品</el-button
|
||||
>
|
||||
<el-button
|
||||
@@ -141,119 +262,5 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<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, Plus, Edit, Refresh, Delete,View } from "@element-plus/icons-vue";
|
||||
import { listGoodsPages, deleteGoods } from "@/api/pms/goods";
|
||||
import { listCascadeCategories } from "@/api/pms/category";
|
||||
import { GoodsItem, GoodsQueryParam } from "@/types";
|
||||
import {moneyFormatter} from '@/utils/filter'
|
||||
|
||||
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: [],
|
||||
goodDetail: undefined,
|
||||
dialogVisible: false,
|
||||
});
|
||||
|
||||
const {
|
||||
loading,
|
||||
multiple,
|
||||
queryParams,
|
||||
goodsList,
|
||||
categoryOptions,
|
||||
goodDetail,
|
||||
total,
|
||||
dialogVisible,
|
||||
} = toRefs(state);
|
||||
|
||||
function handleQuery() {
|
||||
state.loading = true;
|
||||
listGoodsPages(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 deleteGoods(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(() => {
|
||||
listCascadeCategories({}).then((response) => {
|
||||
state.categoryOptions = ref(response.data);
|
||||
});
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,102 +1,9 @@
|
||||
<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.title" 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-show="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="有效期" prop="beginTime">
|
||||
<el-date-picker v-model="formData.beginTime" placeholder="开始时间" value-format="YYYY-MM-DD" />
|
||||
~
|
||||
<el-date-picker v-model="formData.endTime" placeholder="结束时间" 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>
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "advert"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from "vue";
|
||||
@@ -235,3 +142,103 @@ 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.title" 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-show="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="有效期" prop="beginTime">
|
||||
<el-date-picker v-model="formData.beginTime" placeholder="开始时间" value-format="YYYY-MM-DD" />
|
||||
~
|
||||
<el-date-picker v-model="formData.endTime" placeholder="结束时间" 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,3 +1,174 @@
|
||||
<!-- 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, Option } from "@/types";
|
||||
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.$listDictsByCode("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.$listDictsByCode("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 resetForm() {
|
||||
dataFormRef.value.resetFields();
|
||||
state.checkedAuthorizedGrantTypes = [];
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
resetForm();
|
||||
state.dialog.visible = false;
|
||||
}
|
||||
|
||||
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">
|
||||
<!-- 搜索表单 -->
|
||||
@@ -126,168 +297,4 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<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, Option } from "@/types";
|
||||
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.$listDictsByCode("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.$listDictsByCode("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 resetForm() {
|
||||
dataFormRef.value.resetFields();
|
||||
state.checkedAuthorizedGrantTypes = [];
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
resetForm();
|
||||
state.dialog.visible = false;
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -1,85 +1,9 @@
|
||||
<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="single" @click="handleDelete">删除
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入部门名称" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
|
||||
<el-option :value="1" label="正常" />
|
||||
<el-option :value="0" label="禁用" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button class="filter-item" 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="deptList" row-key="id" default-expand-all
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column prop="name" label="部门名称" />
|
||||
<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="200" />
|
||||
|
||||
<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>
|
||||
<el-button type="success" :icon="Plus" circle plain @click.stop="handleAdd(scope.row)">
|
||||
</el-button>
|
||||
|
||||
<el-button type="danger" :icon="Delete" circle plain @click.stop="handleDelete(scope.row)">
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 添加或修改部门对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" @closed="cancel">
|
||||
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="上级部门" prop="parentId">
|
||||
<el-tree-select v-model="formData.parentId" placeholder="选择上级部门" :data="deptOptions" filterable check-strictly />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入部门名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" controls-position="right" style="width: 100px" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门状态">
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "dept"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Vue依赖
|
||||
@@ -92,7 +16,7 @@ import {
|
||||
updateDept,
|
||||
addDept,
|
||||
listSelectDepartments,
|
||||
listTableDepartments,
|
||||
listTableDepartments
|
||||
} from "@/api/system/dept";
|
||||
|
||||
// 组件依赖
|
||||
@@ -195,7 +119,7 @@ async function loadDeptData() {
|
||||
*/
|
||||
function handleAdd(row: any) {
|
||||
loadDeptData();
|
||||
state.formData.id=undefined
|
||||
state.formData.id = undefined
|
||||
state.formData.parentId = row.id;
|
||||
state.dialog = {
|
||||
title: "添加部门",
|
||||
@@ -278,3 +202,85 @@ 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="single" @click="handleDelete">删除
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入部门名称" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
|
||||
<el-option :value="1" label="正常" />
|
||||
<el-option :value="0" label="禁用" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button class="filter-item" 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="deptList" row-key="id" default-expand-all
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column prop="name" label="部门名称" />
|
||||
<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="200" />
|
||||
|
||||
<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>
|
||||
<el-button type="success" :icon="Plus" circle plain @click.stop="handleAdd(scope.row)">
|
||||
</el-button>
|
||||
|
||||
<el-button type="danger" :icon="Delete" circle plain @click.stop="handleDelete(scope.row)">
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 添加或修改部门对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" @closed="cancel">
|
||||
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="上级部门" prop="parentId">
|
||||
<el-tree-select v-model="formData.parentId" placeholder="选择上级部门" :data="deptOptions" filterable check-strictly />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入部门名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" controls-position="right" style="width: 100px" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门状态">
|
||||
<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>
|
||||
|
||||
<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,3 +1,10 @@
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "dict"
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
|
||||
@@ -57,26 +57,30 @@
|
||||
<el-input v-model="formData.name" placeholder="请输入菜单名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="是否外链">
|
||||
<el-radio-group v-model="isExternalPath">
|
||||
<el-radio :label="false">否</el-radio>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
<el-form-item label="菜单类型">
|
||||
<el-radio-group v-model="formData.type" @change="handleMenuTypeChange">
|
||||
<el-radio label="MENU">菜单</el-radio>
|
||||
<el-radio label="CATALOG">目录</el-radio>
|
||||
<el-radio label="EXTLINK">外链</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="isExternalPath" label="外链地址" prop="path">
|
||||
<!-- 路由路径(浏览器地址栏显示) -->
|
||||
<el-form-item v-if="formData.type == 'EXTLINK'" label="外链地址" prop="path">
|
||||
<el-input v-model="formData.path" placeholder="请输入外链完整路径" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="!isExternalPath" label="页面路径" prop="component">
|
||||
<el-form-item v-else label="路由路径" prop="path">
|
||||
<el-input v-if="formData.type == 'CATALOG'" v-model="formData.path" placeholder="/system (注意:目录以/开头)" />
|
||||
<el-input v-else v-model="formData.path" placeholder="user" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 组件页面完整路径 -->
|
||||
<el-form-item v-if="formData.type == 'MENU'" label="组件路径" prop="component">
|
||||
<el-input v-model="formData.component" placeholder="system/user/index" style="width: 95%">
|
||||
<template v-if="formData.parentId != '0'" #prepend>src/views/</template>
|
||||
<template v-if="formData.parentId != '0'" #append>.vue</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip effect="dark" content="请输入组件路径,如果是父组件填写 Layout 即可" placement="right">
|
||||
<i class="el-icon-info" style="margin-left: 10px; color: darkseagreen"></i>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="图标" prop="icon">
|
||||
@@ -93,6 +97,10 @@
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="跳转路由">
|
||||
<el-input v-model="formData.redirect" placeholder="跳转路由路径" maxlength="50" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="formData.visible">
|
||||
<el-radio :label="1">显示</el-radio>
|
||||
@@ -104,9 +112,7 @@
|
||||
<el-input-number v-model="formData.sort" style="width: 100px" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="跳转路径">
|
||||
<el-input v-model="formData.redirect" placeholder="请输入跳转路径" maxlength="50" />
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
@@ -125,7 +131,6 @@ import { reactive, ref, onMounted, toRefs } from "vue";
|
||||
import { Search, Plus, Edit, Refresh, Delete } from "@element-plus/icons-vue";
|
||||
import { ElForm, ElMessage, ElMessageBox, ElPopover } from "element-plus";
|
||||
|
||||
import { isExternal } from "@/utils/validate";
|
||||
import {
|
||||
Dialog,
|
||||
Option,
|
||||
@@ -164,20 +169,28 @@ const state = reactive({
|
||||
dialog: { visible: false } as Dialog,
|
||||
formData: {
|
||||
parentId: "0",
|
||||
name: '',
|
||||
visible: 1,
|
||||
sort: 1,
|
||||
component: "Layout",
|
||||
component: 'Layout',
|
||||
type: 'MENU'
|
||||
} as MenuFormData,
|
||||
rules: {
|
||||
parentId: [{ required: true, message: "请选择顶级菜单", trigger: "blur" }],
|
||||
name: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
|
||||
component: [{ required: true, message: "请输入页面路径", trigger: "blur" }],
|
||||
type: [{ required: true, message: "请选择菜单类型", trigger: "blur" }],
|
||||
path: [{ required: true, message: "请输入路由路径", trigger: "blur" }],
|
||||
component: [{ required: true, message: "请输入组件完整路径", trigger: "blur" }]
|
||||
},
|
||||
menuOptions: [] as Option[],
|
||||
currentRow: undefined,
|
||||
isExternalPath: false,
|
||||
// Icon选择器显示状态
|
||||
iconSelectVisible: false
|
||||
iconSelectVisible: false,
|
||||
cacheData: {
|
||||
menuType: '',
|
||||
menuPath: ''
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const {
|
||||
@@ -188,8 +201,8 @@ const {
|
||||
formData,
|
||||
rules,
|
||||
menuOptions,
|
||||
isExternalPath,
|
||||
iconSelectVisible
|
||||
iconSelectVisible,
|
||||
cacheData
|
||||
} = toRefs(state);
|
||||
|
||||
/**
|
||||
@@ -237,26 +250,29 @@ async function handleAdd(row: any) {
|
||||
title: "添加菜单",
|
||||
visible: true
|
||||
};
|
||||
if (row.id) {
|
||||
// 行点击新增
|
||||
if (row.id) { // 行点击新增
|
||||
|
||||
state.formData.parentId = row.id;
|
||||
if (row.id == '0') {
|
||||
state.formData.component = "Layout";
|
||||
state.formData.type = 'CATALOG';
|
||||
} else {
|
||||
state.formData.component = undefined;
|
||||
state.formData.type = 'MENU';
|
||||
}
|
||||
} else {
|
||||
} else { // 工具栏新增
|
||||
if (state.currentRow) {
|
||||
// 工具栏新增
|
||||
state.formData.parentId = (state.currentRow as any).id;
|
||||
state.formData.component = undefined;
|
||||
state.formData.type = 'MENU';
|
||||
} else {
|
||||
state.formData.parentId = "0";
|
||||
state.formData.component = "Layout";
|
||||
state.formData.type = 'CATALOG';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改弹窗
|
||||
*/
|
||||
async function handleUpdate(row: any) {
|
||||
await loadMenuData();
|
||||
state.dialog = {
|
||||
@@ -266,13 +282,25 @@ async function handleUpdate(row: any) {
|
||||
const id = row.id || state.ids;
|
||||
getMenuDetail(id).then(({ data }) => {
|
||||
state.formData = data;
|
||||
// 判断是否外部链接
|
||||
state.isExternalPath = isExternal(state.formData.path);
|
||||
cacheData.value.menuType = data.type
|
||||
cacheData.value.menuPath = data.path
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单表单提交
|
||||
* 菜单类型change事件
|
||||
*/
|
||||
function handleMenuTypeChange(val: any) {
|
||||
if (val !== cacheData.value.menuType) {
|
||||
formData.value.path = ''
|
||||
} else {
|
||||
formData.value.path = cacheData.value.menuPath
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 菜单提交
|
||||
*/
|
||||
function submitForm() {
|
||||
dataFormRef.value.validate((isValid: boolean) => {
|
||||
@@ -326,7 +354,6 @@ function selected(name: string) {
|
||||
state.iconSelectVisible = false;
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
<template>
|
||||
<div class="menu-container">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-button plain :icon="Switch" @click="toggleExpandAll">展开/折叠</el-button>
|
||||
</el-col>
|
||||
<el-col :span="12" style="text-align: right">
|
||||
<el-button type="primary" :icon="Check" @click="handleSubmit">提交</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-tree class="menu-container__tree" ref="menuRef" v-if="refreshTree" :default-expanded-keys="expandedKeys" :default-expand-all="isExpandAll"
|
||||
:data="menuOptions" show-checkbox node-key="value" empty-text="加载菜单中..." :check-strictly="checkStrictly"
|
||||
highlight-current @node-click="handleNodeClick" />
|
||||
</div>
|
||||
</template>
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "cmenu"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, reactive, ref, toRefs, watch } from "vue";
|
||||
import { listSelectMenus } from "@/api/system/menu";
|
||||
import { listRoleMenuIds, updateRoleMenu } from "@/api/system/role";
|
||||
import { ElTree, ElMessage } from "element-plus";
|
||||
import { Switch, Check } from "@element-plus/icons-vue";
|
||||
import { Switch, Position } from "@element-plus/icons-vue";
|
||||
import { Option } from "@/types";
|
||||
|
||||
const emit = defineEmits(["menuClick"]);
|
||||
const props = defineProps({
|
||||
role: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
default: () => {}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -99,10 +89,25 @@ onMounted(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-button plain :icon="Switch" @click="toggleExpandAll">展开/折叠</el-button>
|
||||
</el-col>
|
||||
<el-col :span="12" style="text-align: right">
|
||||
<el-button type="primary" :icon="Position" @click="handleSubmit">提交</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-tree class="menu-tree" ref="menuRef" v-if="refreshTree" :default-expanded-keys="expandedKeys"
|
||||
:default-expand-all="isExpandAll" :data="menuOptions" show-checkbox node-key="value" empty-text="加载菜单中..."
|
||||
:check-strictly="checkStrictly" highlight-current @node-click="handleNodeClick" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-container {
|
||||
&__tree{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.menu-tree {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
<el-col :span="12" style="text-align: right">
|
||||
<el-button type="primary" :icon="Check" @click="handleSubmit">提交</el-button>
|
||||
<el-button type="primary" :icon="Position" @click="handleSubmit">提交</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@@ -36,7 +36,7 @@ import { onMounted, reactive, toRefs, watch } from "vue";
|
||||
import { listPerms } from "@/api/system/perm";
|
||||
import { listRolePerms, saveRolePerms } from "@/api/system/role";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Check } from "@element-plus/icons-vue";
|
||||
import { Position } from "@element-plus/icons-vue";
|
||||
import { PermQueryParam } from "@/types";
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -1,72 +1,9 @@
|
||||
<template>
|
||||
<div class="role-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="name">
|
||||
<el-input v-model="queryParams.name" 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 ref="dataTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange"
|
||||
@row-click="handleRowClick" highlight-current-row border>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="角色名称" prop="name" />
|
||||
<el-table-column label="角色编码" prop="code" />
|
||||
<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-show="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" @close="cancel" width="450px">
|
||||
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="角色名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入角色名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色编码" prop="code">
|
||||
<el-input v-model="formData.code" placeholder="请输入角色编码" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" controls-position="right" :min="0" style="width: 100px" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态">
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "role"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs } from "vue";
|
||||
@@ -107,7 +44,7 @@ const state = reactive({
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
|
||||
code: [{ required: true, message: "请输入角色编码", trigger: "blur" }],
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
@@ -215,8 +152,77 @@ onMounted(() => {
|
||||
});
|
||||
</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="name">
|
||||
<el-input v-model="queryParams.name" 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 ref="dataTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange"
|
||||
@row-click="handleRowClick" highlight-current-row border>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="角色名称" prop="name" />
|
||||
<el-table-column label="角色编码" prop="code" />
|
||||
<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-show="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" @close="cancel" width="450px">
|
||||
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form-item label="角色名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入角色名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色编码" prop="code">
|
||||
<el-input v-model="formData.code" placeholder="请输入角色编码" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" controls-position="right" :min="0" style="width: 100px" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态">
|
||||
<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>
|
||||
|
||||
<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" scoped>
|
||||
.role-container {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,189 +1,9 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="20">
|
||||
<!-- 部门树 -->
|
||||
<el-col :span="4" :xs="24">
|
||||
<el-card class="box-card">
|
||||
<el-input v-model="deptName" placeholder="部门名称" clearable :prefix-icon="Search" style="margin-bottom: 20px" />
|
||||
<el-tree ref="deptTreeRef" :data="deptOptions" :props="{ children: 'children', label: 'label', disabled: '' }"
|
||||
:expand-on-click-node="false" :filter-node-method="filterDeptNode" default-expand-all
|
||||
@node-click="handleDeptNodeClick"></el-tree>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 用户数据 -->
|
||||
<el-col :span="20" :xs="24">
|
||||
<el-card class="box-card">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-row>
|
||||
<el-col :span="18" :xs="24" >
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd" v-hasPerm="['sys:user:add']">新增</el-button>
|
||||
<el-button type="danger" :icon="Delete" :disabled="multiple" @click="handleDelete"
|
||||
v-hasPerm="['sys:user:delete']">删除</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="keywords">
|
||||
<el-input v-model="queryParams.keywords" placeholder="用户名/昵称/手机号" clearable style="width: 200px"
|
||||
@keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 200px">
|
||||
<el-option label="正常" value="1" />
|
||||
<el-option label="停用" value="0" />
|
||||
</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-col>
|
||||
|
||||
<el-col :span="6" :xs="24" style="text-align: right;">
|
||||
<el-form-item>
|
||||
<el-dropdown split-button style="margin-left: 12px;">
|
||||
导入
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :icon="Download" @click="handleDownloadTemplate">下载模板</el-dropdown-item>
|
||||
<el-dropdown-item :icon="Top" @click="showImportDialog">导入数据</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button :icon="Download" style="margin-left: 12px;" @click="handleExport">导出</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column key="id" label="用户编号" align="center" prop="id" />
|
||||
<el-table-column key="username" label="用户名" align="center" prop="username" />
|
||||
<el-table-column label="用户昵称" align="center" prop="nickname" />
|
||||
|
||||
<el-table-column label="性别" align="center" prop="gender" />
|
||||
|
||||
<el-table-column label="部门" align="center" prop="deptName" />
|
||||
<el-table-column label="手机号码" align="center" prop="mobile" width="120" />
|
||||
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.status" :inactive-value="0" :active-value="1"
|
||||
@change="handleStatusChange(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="gmtCreate" width="180"></el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" :icon="Edit" circle plain @click="handleUpdate(scope.row)"
|
||||
v-hasPerm="['sys:user:edit']"></el-button>
|
||||
<el-button type="danger" :icon="Delete" circle plain @click="handleDelete(scope.row)"
|
||||
v-hasPerm="['sys:user:delete']"></el-button>
|
||||
<el-button type="warning" :icon="Lock" circle plain @click="resetPassword(scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize" @pagination="handleQuery" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="cancel">
|
||||
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input :readonly="!!formData.id" v-model="formData.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="用户昵称" prop="nickname">
|
||||
<el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属部门" prop="deptId">
|
||||
<el-tree-select v-model="formData.deptId" placeholder="请选择所属部门" :data="deptOptions" filterable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="手机号码" prop="mobile">
|
||||
<el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
</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="gender">
|
||||
<el-select v-model="formData.gender" placeholder="请选择">
|
||||
<el-option label="未知" :value="0" />
|
||||
<el-option label="男" :value="1" />
|
||||
<el-option label="女" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色" prop="roleIds">
|
||||
<el-select v-model="formData.roleIds" multiple placeholder="请选择">
|
||||
<el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</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>
|
||||
|
||||
<el-dialog :title="importDialog.title" v-model="importDialog.visible" width="600px" append-to-body
|
||||
@close="closeImportDialog">
|
||||
<el-form ref="importFormRef" :model="importFormData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="所属部门" prop="deptId">
|
||||
<el-tree-select v-model="formData.deptId" placeholder="请选择所属部门" :data="deptOptions" filterable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色" prop="roleIds">
|
||||
<el-select v-model="importFormData.roleIds" multiple placeholder="请选择">
|
||||
<el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Excel">
|
||||
<el-upload class="upload-demo" action="" drag :auto-upload="false"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:file-list="excelFilelist" :on-change="handleExcelChange" :limit="1">
|
||||
<el-icon class="el-icon--upload">
|
||||
<upload-filled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">xls/xlsx files </div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitImportForm">确 定</el-button>
|
||||
<el-button @click="closeImportDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "user"
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang='ts'>
|
||||
// Vue依赖
|
||||
@@ -348,10 +168,10 @@ function filterDeptNode(value: string, data: any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门树节点点击
|
||||
* 部门树节点点击事件
|
||||
*/
|
||||
function handleDeptNodeClick(data: { [key: string]: any }) {
|
||||
state.queryParams.deptId = data.id;
|
||||
state.queryParams.deptId = data.value;
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
@@ -572,7 +392,7 @@ async function showImportDialog() {
|
||||
state.importDialog.visible = true
|
||||
}
|
||||
|
||||
|
||||
// Excel文件上传
|
||||
function handleExcelChange(file: UploadFile) {
|
||||
if (!/\.(xlsx|xls|XLSX|XLS)$/.test(file.name)) {
|
||||
ElMessage.warning('上传Excel只能为xlsx、xls格式');
|
||||
@@ -645,6 +465,192 @@ onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="20">
|
||||
<!-- 部门树 -->
|
||||
<el-col :span="4" :xs="24">
|
||||
<el-card class="box-card">
|
||||
<el-input v-model="deptName" placeholder="部门名称" clearable :prefix-icon="Search" style="margin-bottom: 20px" />
|
||||
<el-tree ref="deptTreeRef" :data="deptOptions" :props="{ children: 'children', label: 'label', disabled: '' }"
|
||||
:expand-on-click-node="false" :filter-node-method="filterDeptNode" default-expand-all
|
||||
@node-click="handleDeptNodeClick"></el-tree>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 用户数据 -->
|
||||
<el-col :span="20" :xs="24">
|
||||
<el-card class="box-card">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-row>
|
||||
<el-col :span="18" :xs="24" >
|
||||
<el-form-item>
|
||||
<el-button type="success" :icon="Plus" @click="handleAdd" v-hasPerm="['sys:user:add']">新增</el-button>
|
||||
<el-button type="danger" :icon="Delete" :disabled="multiple" @click="handleDelete"
|
||||
v-hasPerm="['sys:user:delete']">删除</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="keywords">
|
||||
<el-input v-model="queryParams.keywords" placeholder="用户名/昵称/手机号" clearable style="width: 200px"
|
||||
@keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 200px">
|
||||
<el-option label="正常" value="1" />
|
||||
<el-option label="停用" value="0" />
|
||||
</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-col>
|
||||
|
||||
<el-col :span="6" :xs="24" style="text-align: right;">
|
||||
<el-form-item>
|
||||
<el-dropdown split-button style="margin-left: 12px;">
|
||||
导入
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :icon="Download" @click="handleDownloadTemplate">下载模板</el-dropdown-item>
|
||||
<el-dropdown-item :icon="Top" @click="showImportDialog">导入数据</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button :icon="Download" style="margin-left: 12px;" @click="handleExport">导出</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column key="id" label="用户编号" align="center" prop="id" />
|
||||
<el-table-column key="username" label="用户名" align="center" prop="username" />
|
||||
<el-table-column label="用户昵称" align="center" prop="nickname" />
|
||||
|
||||
<el-table-column label="性别" align="center" prop="gender" />
|
||||
|
||||
<el-table-column label="部门" align="center" prop="deptName" />
|
||||
<el-table-column label="手机号码" align="center" prop="mobile" width="120" />
|
||||
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.status" :inactive-value="0" :active-value="1"
|
||||
@change="handleStatusChange(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="gmtCreate" width="180"></el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" :icon="Edit" circle plain @click="handleUpdate(scope.row)"
|
||||
v-hasPerm="['sys:user:edit']"></el-button>
|
||||
<el-button type="danger" :icon="Delete" circle plain @click="handleDelete(scope.row)"
|
||||
v-hasPerm="['sys:user:delete']"></el-button>
|
||||
<el-button type="warning" :icon="Lock" circle plain @click="resetPassword(scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize" @pagination="handleQuery" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="cancel">
|
||||
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input :readonly="!!formData.id" v-model="formData.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="用户昵称" prop="nickname">
|
||||
<el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属部门" prop="deptId">
|
||||
<el-tree-select v-model="formData.deptId" placeholder="请选择所属部门" :data="deptOptions" filterable check-strictly />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="手机号码" prop="mobile">
|
||||
<el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
</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="gender">
|
||||
<el-select v-model="formData.gender" placeholder="请选择">
|
||||
<el-option label="未知" :value="0" />
|
||||
<el-option label="男" :value="1" />
|
||||
<el-option label="女" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色" prop="roleIds">
|
||||
<el-select v-model="formData.roleIds" multiple placeholder="请选择">
|
||||
<el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</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>
|
||||
|
||||
<el-dialog :title="importDialog.title" v-model="importDialog.visible" width="600px" append-to-body
|
||||
@close="closeImportDialog">
|
||||
<el-form ref="importFormRef" :model="importFormData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="部门" prop="deptId">
|
||||
<el-tree-select v-model="formData.deptId" placeholder="请选择部门" :data="deptOptions" filterable check-strictly />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色" prop="roleIds">
|
||||
<el-select v-model="importFormData.roleIds" multiple placeholder="请选择">
|
||||
<el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Excel">
|
||||
<el-upload class="upload-demo" action="" drag :auto-upload="false"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:file-list="excelFilelist" :on-change="handleExcelChange" :limit="1">
|
||||
<el-icon class="el-icon--upload">
|
||||
<upload-filled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">xls/xlsx files </div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitImportForm">确 定</el-button>
|
||||
<el-button @click="closeImportDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,67 @@
|
||||
<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
|
||||
<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";
|
||||
|
||||
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">
|
||||
@@ -81,62 +145,5 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, onMounted, toRefs } from "vue";
|
||||
import { ElTable } from "element-plus";
|
||||
import { Search, Refresh } from "@element-plus/icons-vue";
|
||||
|
||||
import { listMemeberPages } from "@/api/ums/member";
|
||||
import { MemberQueryParam, MemberItem } from "@/types";
|
||||
|
||||
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;
|
||||
listMemeberPages(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>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user