Skip to content

Commit a99a125

Browse files
YunaiVgitee-org
authored andcommitted
!207 会员管理:增加会员标签功能
Merge pull request !207 from 疯狂的世界/member_dev
2 parents 848b668 + 2964d55 commit a99a125

File tree

6 files changed

+399
-3
lines changed

6 files changed

+399
-3
lines changed

src/api/member/tag/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import request from '@/config/axios'
2+
3+
export interface TagVO {
4+
id: number
5+
name: string
6+
}
7+
8+
// 查询会员标签列表
9+
export const getMemberTagPage = async (params) => {
10+
return await request.get({ url: `/member/tag/page`, params })
11+
}
12+
13+
// 查询会员标签详情
14+
export const getMemberTag = async (id: number) => {
15+
return await request.get({ url: `/member/tag/get?id=` + id })
16+
}
17+
18+
// 新增会员标签
19+
export const createMemberTag = async (data: TagVO) => {
20+
return await request.post({ url: `/member/tag/create`, data })
21+
}
22+
23+
// 修改会员标签
24+
export const updateMemberTag = async (data: TagVO) => {
25+
return await request.put({ url: `/member/tag/update`, data })
26+
}
27+
28+
// 删除会员标签
29+
export const deleteMemberTag = async (id: number) => {
30+
return await request.delete({ url: `/member/tag/delete?id=` + id })
31+
}
32+
33+
// 导出会员标签 Excel
34+
export const exportMemberTag = async (params) => {
35+
return await request.download({ url: `/member/tag/export-excel`, params })
36+
}

src/views/member/tag/TagForm.vue

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<template>
2+
<Dialog :title="dialogTitle" v-model="dialogVisible">
3+
<el-form
4+
ref="formRef"
5+
:model="formData"
6+
:rules="formRules"
7+
label-width="100px"
8+
v-loading="formLoading"
9+
>
10+
<el-form-item label="标签名称" prop="name">
11+
<el-input v-model="formData.name" placeholder="请输入标签名称" />
12+
</el-form-item>
13+
</el-form>
14+
<template #footer>
15+
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
16+
<el-button @click="dialogVisible = false">取 消</el-button>
17+
</template>
18+
</Dialog>
19+
</template>
20+
<script setup lang="ts">
21+
import * as TagApi from '@/api/member/tag'
22+
23+
const { t } = useI18n() // 国际化
24+
const message = useMessage() // 消息弹窗
25+
26+
const dialogVisible = ref(false) // 弹窗的是否展示
27+
const dialogTitle = ref('') // 弹窗的标题
28+
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
29+
const formType = ref('') // 表单的类型:create - 新增;update - 修改
30+
const formData = ref({
31+
id: undefined,
32+
name: undefined
33+
})
34+
const formRules = reactive({
35+
name: [{ required: true, message: '标签名称不能为空', trigger: 'blur' }]
36+
})
37+
const formRef = ref() // 表单 Ref
38+
39+
/** 打开弹窗 */
40+
const open = async (type: string, id?: number) => {
41+
dialogVisible.value = true
42+
dialogTitle.value = t('action.' + type)
43+
formType.value = type
44+
resetForm()
45+
// 修改时,设置数据
46+
if (id) {
47+
formLoading.value = true
48+
try {
49+
formData.value = await TagApi.getMemberTag(id)
50+
} finally {
51+
formLoading.value = false
52+
}
53+
}
54+
}
55+
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
56+
57+
/** 提交表单 */
58+
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
59+
const submitForm = async () => {
60+
// 校验表单
61+
if (!formRef) return
62+
const valid = await formRef.value.validate()
63+
if (!valid) return
64+
// 提交请求
65+
formLoading.value = true
66+
try {
67+
const data = formData.value as unknown as TagApi.TagVO
68+
if (formType.value === 'create') {
69+
await TagApi.createMemberTag(data)
70+
message.success(t('common.createSuccess'))
71+
} else {
72+
await TagApi.updateMemberTag(data)
73+
message.success(t('common.updateSuccess'))
74+
}
75+
dialogVisible.value = false
76+
// 发送操作成功的事件
77+
emit('success')
78+
} finally {
79+
formLoading.value = false
80+
}
81+
}
82+
83+
/** 重置表单 */
84+
const resetForm = () => {
85+
formData.value = {
86+
id: undefined,
87+
name: undefined
88+
}
89+
formRef.value?.resetFields()
90+
}
91+
</script>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<template>
2+
<el-select v-model="tagIds" placeholder="请选择用户标签" clearable multiple class="!w-240px">
3+
<el-option v-for="tag in tags" :key="tag.id" :label="tag.name" :value="tag.id" />
4+
</el-select>
5+
<el-button
6+
v-if="showAdd"
7+
type="primary"
8+
class="ml-2"
9+
link
10+
@click="openForm('create')"
11+
v-hasPermi="['member:tag:create']"
12+
>
13+
新增标签
14+
</el-button>
15+
16+
<!-- 表单弹窗:添加 -->
17+
<TagForm ref="formRef" @success="getList" />
18+
</template>
19+
20+
<script lang="ts" setup>
21+
import * as TagApi from '@/api/member/tag'
22+
import TagForm from '@/views/member/tag/TagForm.vue'
23+
24+
defineOptions({ name: 'MemberTagSelect' })
25+
26+
const props = defineProps({
27+
/** 下拉框选中值 **/
28+
modelValue: {
29+
type: Array,
30+
default: undefined
31+
},
32+
/** 是否显示“新增标签”按钮 **/
33+
showAdd: {
34+
type: Boolean,
35+
default: false
36+
}
37+
})
38+
const emit = defineEmits(['update:modelValue'])
39+
defineExpose({
40+
showAdd: props.showAdd
41+
})
42+
43+
const tagIds = computed({
44+
get() {
45+
return props.modelValue
46+
},
47+
set(value: any) {
48+
emit('update:modelValue', value)
49+
}
50+
})
51+
52+
const tags = ref<TagApi.TagVO[]>([])
53+
54+
const getList = async () => {
55+
const data = await TagApi.getMemberTagPage({})
56+
tags.value = data.list
57+
}
58+
59+
/** 添加用户标签表单弹框 */
60+
const formRef = ref()
61+
const openForm = (type: string, id?: number) => {
62+
formRef.value.open(type, id)
63+
}
64+
65+
/** 初始化 */
66+
onMounted(() => {
67+
getList()
68+
})
69+
</script>

src/views/member/tag/index.vue

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<template>
2+
<ContentWrap>
3+
<!-- 搜索工作栏 -->
4+
<el-form
5+
class="-mb-15px"
6+
:model="queryParams"
7+
ref="queryFormRef"
8+
:inline="true"
9+
label-width="68px"
10+
>
11+
<el-form-item label="标签名称" prop="name">
12+
<el-input
13+
v-model="queryParams.name"
14+
placeholder="请输入标签名称"
15+
clearable
16+
@keyup.enter="handleQuery"
17+
class="!w-240px"
18+
/>
19+
</el-form-item>
20+
<el-form-item label="创建时间" prop="createTime">
21+
<el-date-picker
22+
v-model="queryParams.createTime"
23+
value-format="YYYY-MM-DD HH:mm:ss"
24+
type="daterange"
25+
start-placeholder="开始日期"
26+
end-placeholder="结束日期"
27+
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
28+
class="!w-240px"
29+
/>
30+
</el-form-item>
31+
<el-form-item>
32+
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
33+
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
34+
<el-button type="primary" @click="openForm('create')" v-hasPermi="['member:tag:create']">
35+
<Icon icon="ep:plus" class="mr-5px" /> 新增
36+
</el-button>
37+
<el-button
38+
type="success"
39+
plain
40+
@click="handleExport"
41+
:loading="exportLoading"
42+
v-hasPermi="['member:tag:export']"
43+
>
44+
<Icon icon="ep:download" class="mr-5px" /> 导出
45+
</el-button>
46+
</el-form-item>
47+
</el-form>
48+
</ContentWrap>
49+
50+
<!-- 列表 -->
51+
<ContentWrap>
52+
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
53+
<el-table-column label="序号" type="index" width="70px" />
54+
<el-table-column label="编号" align="center" prop="id" width="150px" />
55+
<el-table-column label="标签名称" align="center" prop="name" />
56+
<el-table-column
57+
label="创建时间"
58+
align="center"
59+
prop="createTime"
60+
:formatter="dateFormatter"
61+
width="180px"
62+
/>
63+
<el-table-column label="操作" align="center" width="150px">
64+
<template #default="scope">
65+
<el-button
66+
link
67+
type="primary"
68+
@click="openForm('update', scope.row.id)"
69+
v-hasPermi="['member:tag:update']"
70+
>
71+
编辑
72+
</el-button>
73+
<el-button
74+
link
75+
type="danger"
76+
@click="handleDelete(scope.row.id)"
77+
v-hasPermi="['member:tag:delete']"
78+
>
79+
删除
80+
</el-button>
81+
</template>
82+
</el-table-column>
83+
</el-table>
84+
<!-- 分页 -->
85+
<Pagination
86+
:total="total"
87+
v-model:page="queryParams.pageNo"
88+
v-model:limit="queryParams.pageSize"
89+
@pagination="getList"
90+
/>
91+
</ContentWrap>
92+
93+
<!-- 表单弹窗:添加/修改 -->
94+
<TagForm ref="formRef" @success="getList" />
95+
</template>
96+
97+
<script setup lang="ts" name="MemberTag">
98+
import { dateFormatter } from '@/utils/formatTime'
99+
import download from '@/utils/download'
100+
import * as TagApi from '@/api/member/tag'
101+
import TagForm from './TagForm.vue'
102+
const message = useMessage() // 消息弹窗
103+
const { t } = useI18n() // 国际化
104+
105+
const loading = ref(true) // 列表的加载中
106+
const total = ref(0) // 列表的总页数
107+
const list = ref([]) // 列表的数据
108+
const queryParams = reactive({
109+
pageNo: 1,
110+
pageSize: 10,
111+
name: null,
112+
createTime: []
113+
})
114+
const queryFormRef = ref() // 搜索的表单
115+
const exportLoading = ref(false) // 导出的加载中
116+
117+
/** 查询列表 */
118+
const getList = async () => {
119+
loading.value = true
120+
try {
121+
const data = await TagApi.getMemberTagPage(queryParams)
122+
list.value = data.list
123+
total.value = data.total
124+
} finally {
125+
loading.value = false
126+
}
127+
}
128+
129+
/** 搜索按钮操作 */
130+
const handleQuery = () => {
131+
queryParams.pageNo = 1
132+
getList()
133+
}
134+
135+
/** 重置按钮操作 */
136+
const resetQuery = () => {
137+
queryFormRef.value.resetFields()
138+
handleQuery()
139+
}
140+
141+
/** 添加/修改操作 */
142+
const formRef = ref()
143+
const openForm = (type: string, id?: number) => {
144+
formRef.value.open(type, id)
145+
}
146+
147+
/** 删除按钮操作 */
148+
const handleDelete = async (id: number) => {
149+
try {
150+
// 删除的二次确认
151+
await message.delConfirm()
152+
// 发起删除
153+
await TagApi.deleteMemberTag(id)
154+
message.success(t('common.delSuccess'))
155+
// 刷新列表
156+
await getList()
157+
} catch {}
158+
}
159+
160+
/** 导出按钮操作 */
161+
const handleExport = async () => {
162+
try {
163+
// 导出的二次确认
164+
await message.exportConfirm()
165+
// 发起导出
166+
exportLoading.value = true
167+
const data = await TagApi.exportMemberTag(queryParams)
168+
download.excel(data, '会员标签.xls')
169+
} catch {
170+
} finally {
171+
exportLoading.value = false
172+
}
173+
}
174+
175+
/** 初始化 **/
176+
onMounted(() => {
177+
getList()
178+
})
179+
</script>

0 commit comments

Comments
 (0)