495 lines
12 KiB
Vue
495 lines
12 KiB
Vue
<template>
|
||
<CommonPage show-footer :title="$route.title">
|
||
<!-- {{ queryData }} -->
|
||
<n-row gutter="12">
|
||
<n-col :span="24">
|
||
<div flex>
|
||
<n-card w-500>
|
||
<n-statistic label="未激活" tabular-nums>
|
||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.total" />
|
||
</n-statistic>
|
||
</n-card>
|
||
<n-card ml-10 w-500>
|
||
<n-statistic label="已激活" tabular-nums>
|
||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.service" />
|
||
</n-statistic>
|
||
</n-card>
|
||
<n-card ml-10 w-500>
|
||
<n-statistic label="未领取" tabular-nums>
|
||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.count" />
|
||
</n-statistic>
|
||
</n-card>
|
||
<n-card ml-10 w-500>
|
||
<n-statistic label="已领取" tabular-nums>
|
||
<n-number-animation ref="numberAnimationInstRef" :from="0" :to="cardData.count" />
|
||
</n-statistic>
|
||
</n-card>
|
||
</div>
|
||
</n-col>
|
||
<n-col :span="24">
|
||
<div mt-10>
|
||
<span>激活状态:</span>
|
||
<n-radio-group v-model:value="queryData.status">
|
||
<n-radio-button
|
||
v-for="song in songs"
|
||
:key="song.value"
|
||
:value="song.value"
|
||
:label="song.label"
|
||
/>
|
||
</n-radio-group>
|
||
</div>
|
||
</n-col>
|
||
<n-col :span="24">
|
||
<div mt-10>
|
||
<span>领取状态:</span>
|
||
<n-radio-group v-model:value="queryData.status1">
|
||
<n-radio-button
|
||
v-for="song in songs1"
|
||
:key="song.value"
|
||
:value="song.value"
|
||
:label="song.label"
|
||
/>
|
||
</n-radio-group>
|
||
</div>
|
||
</n-col>
|
||
<n-col :span="24">
|
||
<div mt-10 flex items-center>
|
||
<div w-100>关键字搜索:</div>
|
||
<n-input-group>
|
||
<n-select
|
||
v-model:value="queryData.selectKey"
|
||
:style="{ width: '15%' }"
|
||
:options="selectOptions"
|
||
placeholder="请选择"
|
||
/>
|
||
<n-input v-model:value="queryData.word" :style="{ width: '20%' }" />
|
||
</n-input-group>
|
||
</div>
|
||
</n-col>
|
||
<n-col :span="10">
|
||
<div mt-10 flex items-center>
|
||
<span w-100>时间搜索:</span>
|
||
<n-date-picker
|
||
v-model:formatted-value="queryData.time"
|
||
value-format="yyyy-MM-dd HH:mm:ss"
|
||
type="datetimerange"
|
||
clearable
|
||
/>
|
||
</div>
|
||
</n-col>
|
||
<n-col :span="24">
|
||
<div mt-10>
|
||
<n-button v-perms="['/admin/qrcode/add']" mr-10 type="primary" @click="openModal(1)">
|
||
新增二维码
|
||
</n-button>
|
||
<n-button v-perms="['/admin/qrcode/edit']" mr-10 type="warning" @click="openModal(2)">
|
||
修改二维码
|
||
</n-button>
|
||
<n-button mr-10 type="info" @click="saveCode">下载二维码</n-button>
|
||
<!-- <n-button mr-10 type="primary" @click="openModal(1)">新增二维码</n-button> -->
|
||
<!-- <n-button mr-10 type="warning" @click="openModal(3)">修改二维码</n-button> -->
|
||
<n-button type="primary" @click="getList">搜索</n-button>
|
||
<n-button ml-10 @click="clear">重置</n-button>
|
||
</div>
|
||
</n-col>
|
||
</n-row>
|
||
<n-data-table
|
||
class="mt-5"
|
||
:loading="loading"
|
||
:columns="columns"
|
||
:data="data"
|
||
:pagination="pagination"
|
||
:bordered="false"
|
||
:row-key="rowKey"
|
||
:checked-row-keys="checkedRowKeysRef"
|
||
remote
|
||
@update:checked-row-keys="handleCheck"
|
||
/>
|
||
<n-modal v-model:show="showModal" :auto-focus="false">
|
||
<n-card
|
||
style="width: 600px"
|
||
:title="modelTitle"
|
||
:bordered="false"
|
||
size="huge"
|
||
role="dialog"
|
||
aria-modal="true"
|
||
>
|
||
<n-form ref="formRef" label-placement="left" :model="formValue" :rules="rules">
|
||
<n-form-item v-if="modalType === 1" label="新增数量:" path="number">
|
||
<n-input-number v-model:value="formValue.number" :min="1" clearable />
|
||
</n-form-item>
|
||
<n-form-item label="赠送豆子:" path="pulse">
|
||
<n-input-number v-model:value="formValue.pulse" :min="1" clearable />
|
||
</n-form-item>
|
||
<n-form-item label="激活状态:" path="activate_status">
|
||
<n-switch
|
||
v-model:value="formValue.activate_status"
|
||
:checked-value="1"
|
||
:unchecked-value="2"
|
||
/>
|
||
</n-form-item>
|
||
<n-form-item>
|
||
<div class="m-auto">
|
||
<n-button
|
||
class="m-auto"
|
||
type="primary"
|
||
attr-type="button"
|
||
@click="handleValidateClick"
|
||
>
|
||
提交
|
||
</n-button>
|
||
<n-button class="ml-10" @click="handleclear">取消</n-button>
|
||
</div>
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
</n-modal>
|
||
</CommonPage>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { NButton } from 'naive-ui'
|
||
import JSZip from 'jszip'
|
||
import { saveAs } from 'file-saver'
|
||
import api from '../api'
|
||
import { ref, resolveDirective, withDirectives } from 'vue'
|
||
|
||
const vPerms = resolveDirective('perms')
|
||
|
||
const songs = ref([
|
||
{
|
||
value: 1,
|
||
label: '已激活',
|
||
},
|
||
{
|
||
value: 2,
|
||
label: '未激活',
|
||
},
|
||
])
|
||
|
||
const songs1 = ref([
|
||
{
|
||
value: 1,
|
||
label: '已领取',
|
||
},
|
||
{
|
||
value: 2,
|
||
label: '未领取',
|
||
},
|
||
])
|
||
|
||
const selectOptions = ref([
|
||
{
|
||
value: 0,
|
||
label: 'ID',
|
||
},
|
||
{
|
||
value: 1,
|
||
label: '手机号',
|
||
},
|
||
])
|
||
const queryData = ref({
|
||
status: '',
|
||
status1: '',
|
||
time: null,
|
||
word: '',
|
||
selectKey: null,
|
||
})
|
||
|
||
const cardData = ref({})
|
||
|
||
const columns = ref([
|
||
{
|
||
type: 'selection',
|
||
},
|
||
{
|
||
title: 'ID',
|
||
align: 'center',
|
||
key: 'qid',
|
||
},
|
||
{
|
||
title: '二维码',
|
||
align: 'center',
|
||
slot: 'qrcode',
|
||
render(row) {
|
||
return h('img', {
|
||
src: row.url,
|
||
style: {
|
||
width: '50px',
|
||
height: '50px',
|
||
},
|
||
})
|
||
},
|
||
},
|
||
{
|
||
title: '用户',
|
||
align: 'center',
|
||
slot: 'user_name',
|
||
render(row) {
|
||
return h('span', row.User.nickName)
|
||
},
|
||
},
|
||
{
|
||
title: '用户电话',
|
||
align: 'center',
|
||
slot: 'phone',
|
||
render(row) {
|
||
return h('span', row.User.phone)
|
||
},
|
||
},
|
||
{
|
||
title: '赠送豆子',
|
||
align: 'center',
|
||
key: 'pulse',
|
||
},
|
||
{
|
||
title: '激活状态',
|
||
align: 'center',
|
||
slot: 'status',
|
||
render(row) {
|
||
switch (row.activate_status) {
|
||
case 1:
|
||
return h('span', '已激活')
|
||
case 2:
|
||
return h('span', '未激活')
|
||
}
|
||
},
|
||
},
|
||
{
|
||
title: '领取状态',
|
||
align: 'center',
|
||
slot: 'status',
|
||
render(row) {
|
||
switch (row.use_status) {
|
||
case 1:
|
||
return h('span', '已领取')
|
||
case 2:
|
||
return h('span', '未领取')
|
||
}
|
||
},
|
||
},
|
||
{
|
||
title: '激活时间',
|
||
align: 'center',
|
||
key: 'activate_time',
|
||
},
|
||
{
|
||
title: '领取时间',
|
||
align: 'center',
|
||
key: 'use_time',
|
||
},
|
||
{
|
||
title: '操作',
|
||
align: 'center',
|
||
slot: 'action',
|
||
render(row) {
|
||
if (row.use_status === 2) {
|
||
return withDirectives(
|
||
h(
|
||
NButton,
|
||
{
|
||
type: 'primary',
|
||
size: 'small',
|
||
onClick: () => openModal(2, row),
|
||
},
|
||
{
|
||
default: () => '编辑',
|
||
}
|
||
),
|
||
[[vPerms, ['/admin/qrcode/edit']]]
|
||
)
|
||
// return h(
|
||
// NButton,
|
||
// {
|
||
// type: 'primary',
|
||
// size: 'small',
|
||
// onClick: () => {
|
||
// openModal(2, row)
|
||
// },
|
||
// },
|
||
// {
|
||
// default: () => '编辑',
|
||
// }
|
||
// )
|
||
}
|
||
},
|
||
},
|
||
])
|
||
|
||
const data = ref([])
|
||
|
||
const pagination = ref({
|
||
page: 1,
|
||
pageSize: 10,
|
||
itemCount: 0,
|
||
prefix: ({ itemCount }) => {
|
||
return `共 ${itemCount} 项`
|
||
},
|
||
onChange: (page) => {
|
||
pagination.value.page = page
|
||
getList()
|
||
},
|
||
onUpdatePageSize: (pageSize) => {
|
||
pagination.value.pageSize = pageSize
|
||
pagination.value.page = 1
|
||
getList()
|
||
},
|
||
})
|
||
|
||
onMounted(() => {
|
||
getList()
|
||
})
|
||
|
||
const loading = ref(false)
|
||
|
||
const getList = async () => {
|
||
loading.value = true
|
||
try {
|
||
const query_data = {
|
||
UseStatus: queryData.value.status,
|
||
ActivateStatus: queryData.value.status1,
|
||
StartTime: queryData.value.time === null ? '' : queryData.value.time[0] || '',
|
||
EndTime: queryData.value.time === null ? '' : queryData.value.time[1] || '',
|
||
}
|
||
switch (queryData.value.selectKey) {
|
||
case 0:
|
||
query_data['Qid'] = queryData.value.word
|
||
break
|
||
case 1:
|
||
query_data['Phone'] = queryData.value.word
|
||
break
|
||
}
|
||
const res = await api.getCodelist({
|
||
pageNum: pagination.value.page,
|
||
pageSize: pagination.value.pageSize,
|
||
...query_data,
|
||
})
|
||
data.value = res.data.data || []
|
||
pagination.value.itemCount = res.data.total
|
||
cardData.value.total = res.data.number
|
||
cardData.value.service = res.data.commission
|
||
cardData.value.count = 0
|
||
} catch (error) {
|
||
$message.error(error.msg)
|
||
}
|
||
loading.value = false
|
||
}
|
||
|
||
const clear = () => {
|
||
queryData.value = {
|
||
status: '',
|
||
status1: '',
|
||
time: null,
|
||
word: '',
|
||
selectKey: null,
|
||
}
|
||
getList()
|
||
}
|
||
|
||
const rowKey = (row) => row.qid
|
||
|
||
const checkedRowKeysRef = ref([])
|
||
|
||
const handleCheck = (rowKeys) => {
|
||
checkedRowKeysRef.value = rowKeys
|
||
}
|
||
|
||
const showModal = ref(false)
|
||
|
||
const modelTitle = ref('')
|
||
|
||
const formValue = ref({
|
||
number: null,
|
||
pulse: null,
|
||
activate_status: 2,
|
||
})
|
||
|
||
const rules = {
|
||
number: {
|
||
required: true,
|
||
type: 'number',
|
||
message: '请输入生成数量',
|
||
trigger: 'blur',
|
||
},
|
||
pulse: {
|
||
required: true,
|
||
type: 'number',
|
||
message: '请输入豆子数量',
|
||
trigger: 'blur',
|
||
},
|
||
}
|
||
|
||
const handleclear = () => {
|
||
showModal.value = false
|
||
formValue.value = {
|
||
number: null,
|
||
pulse: null,
|
||
activate_status: 2,
|
||
}
|
||
checkedRowKeysRef.value = []
|
||
}
|
||
|
||
const modalType = ref(null)
|
||
const nowRow = ref([])
|
||
|
||
const openModal = (e, row) => {
|
||
showModal.value = true
|
||
modalType.value = e
|
||
modelTitle.value = e === 1 ? '新增二维码' : '编辑二维码'
|
||
if (e === 2) {
|
||
nowRow.value = [row.qid]
|
||
formValue.value.pulse = row.pulse
|
||
formValue.value.activate_status = row.activate_status
|
||
} else if (e === 3) {
|
||
nowRow.value = checkedRowKeysRef.value
|
||
}
|
||
}
|
||
|
||
const formRef = ref(null)
|
||
|
||
const handleValidateClick = (e) => {
|
||
e.preventDefault()
|
||
formRef.value?.validate(async (errors) => {
|
||
if (!errors) {
|
||
try {
|
||
if (modalType.value === 1) {
|
||
await api.addCode(formValue.value)
|
||
} else {
|
||
await api.updateCode({
|
||
qid: nowRow.value,
|
||
...formValue.value,
|
||
})
|
||
}
|
||
handleclear()
|
||
getList()
|
||
} catch (error) {
|
||
// $message.error(error.msg)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 下载二维码
|
||
const saveCode = async () => {
|
||
if (checkedRowKeysRef.value.length === 0) return $message.error('请选择二维码')
|
||
|
||
const zip = new JSZip()
|
||
|
||
data.value.forEach((item) => {
|
||
checkedRowKeysRef.value.forEach((id) => {
|
||
if (item.qid === id) {
|
||
const imageData = item.url.split(',')[1]
|
||
zip.file(`${item.qid}.png`, imageData, {
|
||
base64: true,
|
||
})
|
||
}
|
||
})
|
||
})
|
||
|
||
const content = await zip.generateAsync({ type: 'blob' })
|
||
saveAs(content, '二维码.zip')
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped></style>
|