17 changed files with 475 additions and 1101 deletions
-
104src/router/index.js
-
9src/utils/menuTreePermission.js
-
9src/utils/menuUtils.js
-
244src/views/history/history.vue
-
119src/views/history/newHistory.vue
-
117src/views/history/oldHistory.vue
-
35src/views/permissions/permissions.vue
-
25src/views/permissions/rolePermission.vue
-
64src/views/permissions/userPermission.vue
-
5src/views/refund/gold/addCoinRefund.vue
-
726src/views/refund/gold/addNewCoinRefund.vue
-
8src/views/refund/gold/coinRefund.vue
-
23src/views/refund/gold/coinRefundDetail.vue
-
9src/views/usergold/bean/userbean.vue
-
4src/views/usergold/gold/clientCount.vue
-
22src/views/usergold/gold/clientCountBalance.vue
-
53src/views/usergold/gold/clientCountDetail.vue
@ -1,179 +1,71 @@ |
|||
<template> |
|||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick"> |
|||
<el-tab-pane label="金币查询(新)" name="new"></el-tab-pane> |
|||
<el-tab-pane label="金币查询(旧)" name="old"></el-tab-pane> |
|||
</el-tabs> |
|||
<el-card> |
|||
<el-text size="large">姓名:</el-text> |
|||
<el-input v-model="searchObj.name" placeholder="请输入姓名" style="width: 12vw;margin-right:1vw" |
|||
clearable></el-input> |
|||
|
|||
<el-text size="large">精网号:</el-text> |
|||
<el-input v-model="searchObj.jwcode" placeholder="请输入精网号" style="width: 12vw;margin-right:1vw" |
|||
clearable></el-input> |
|||
|
|||
<el-text size="large" style="width: 80px">更新时间:</el-text> |
|||
<el-date-picker v-model="dateRange" type="datetimerange" :default-time="defaultTime" range-separator="至" |
|||
start-placeholder="开始时间" end-placeholder="结束时间" style="width: 25vw;margin-right:1vw" /> |
|||
|
|||
<el-button type="success" @click="resetSearch">重置</el-button> |
|||
<el-button type="primary" v-if="activeName == 'new'" @click="get">查询</el-button> |
|||
<el-button type="primary" v-else-if="activeName == 'old'" @click="getOld">查询</el-button> |
|||
</el-card> |
|||
|
|||
<el-card style="margin-top:10px" v-show="tableData.length > 0"> |
|||
<el-table :data="tableData" style="width: 82vw;height:60vh"> |
|||
<el-table-column type="index" label="序号" width="100" header-align="center" align="center"> |
|||
<template #default="scope"> |
|||
{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="客户姓名" width="180" show-overflow-tooltip /> |
|||
<el-table-column prop="jwcode" label="精网号" width="180" header-align="center" align="center" /> |
|||
<el-table-column prop="num" label="数量" width="180" header-align="center" align="center" /> |
|||
<el-table-column prop="updateType" show-overflow-tooltip label="更新类型" width="180" align="center" /> |
|||
<el-table-column v-if="activeName === 'new'" prop="freeGold" label="免费金币" width="180" align="center" /> |
|||
<el-table-column v-if="activeName === 'new'" prop="permanentGold" label="永久金币" width="180" align="center" /> |
|||
<el-table-column v-if="activeName === 'new'" prop="taskGold" label="任务金币" width="180" align="center" /> |
|||
<el-table-column prop="operator" label="操作人" width="180" /> |
|||
<el-table-column prop="createTime" label="更新时间" width="200" header-align="center" align="center" /> |
|||
<el-table-column prop="remark" label="备注" show-overflow-tooltip width="200" align="center" /> |
|||
</el-table> |
|||
<el-pagination background style="margin-top:20px" v-model:current-page="pagination.pageNum" |
|||
v-model:page-size="pagination.pageSize" layout="total, sizes, prev, pager, next, jumper" |
|||
:total="pagination.total" @size-change="handlePageSizeChange" |
|||
@current-change="handleCurrentChange"></el-pagination> |
|||
</el-card> |
|||
</template> |
|||
<script setup> |
|||
import { onMounted, ref } from 'vue' |
|||
import { ElMessage } from 'element-plus' |
|||
import API from '@/util/http.js' |
|||
import moment from 'moment' |
|||
import { useAdminStore } from "@/store/index.js" |
|||
import { storeToRefs } from "pinia" |
|||
import dayjs from 'dayjs' |
|||
const adminStore = useAdminStore() |
|||
const { adminData, menuTree } = storeToRefs(adminStore) |
|||
import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js" |
|||
const defaultTime = [ |
|||
new Date(2000, 1, 1, 0, 0, 0), |
|||
new Date(2000, 2, 1, 23, 59, 59), |
|||
] |
|||
const activeName = ref('new') |
|||
const handleClick = function (tab) { |
|||
activeName.value = tab.props.name |
|||
if (tab.props.name === 'new') { |
|||
resetSearch() |
|||
pagination.value.pageNum = 1 |
|||
tableData.value = [] |
|||
console.log('新的'); |
|||
} else if (tab.props.name === 'old') { |
|||
resetSearch() |
|||
pagination.value.pageNum = 1 |
|||
console.log('旧的'); |
|||
tableData.value = [] |
|||
<router-view></router-view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref, watch} from 'vue'; |
|||
import {useRoute, useRouter} from 'vue-router'; |
|||
import {storeToRefs} from "pinia"; |
|||
import {useAdminStore} from "@/store/index.js"; |
|||
import {hasMenuPermission, permissionMapping} from "@/utils/menuTreePermission.js"; |
|||
|
|||
const router = useRouter(); |
|||
const route = useRoute(); |
|||
const adminStore = useAdminStore(); |
|||
const {menuTree} = storeToRefs(adminStore); |
|||
|
|||
const activeTab = ref(''); |
|||
const hasNew = ref(false); |
|||
const hasOld = ref(false); |
|||
// 导航方法 |
|||
const navigateTo = (name) => { |
|||
activeTab.value = name; |
|||
router.push({name}); |
|||
}; |
|||
|
|||
|
|||
// 初始化权限状态 |
|||
const initPermissions = () => { |
|||
if (!menuTree.value || !menuTree.value.length) return |
|||
|
|||
hasNew.value = hasMenuPermission(menuTree.value, permissionMapping.newCoinSelect) |
|||
hasOld.value = hasMenuPermission(menuTree.value, permissionMapping.oldCoinSelect) |
|||
} |
|||
|
|||
// 默认跳转逻辑 |
|||
const getDefaultAuditRoute = () => { |
|||
initPermissions() |
|||
if (hasNew.value) return 'newHistory' |
|||
if (hasOld.value) return 'oldHistory' |
|||
return 'newHistory' |
|||
}; |
|||
|
|||
// 监听路由变化更新标签状态 |
|||
watch(() => route.name, (newName) => { |
|||
initPermissions() |
|||
if (newName === 'newHistory' || newName === 'oldHistory') { |
|||
activeTab.value = newName; |
|||
} else if (newName === 'history') { |
|||
// 每次访问 /history 都进行默认跳转 |
|||
const defaultRoute = getDefaultAuditRoute(); |
|||
navigateTo(defaultRoute); |
|||
} |
|||
} |
|||
const tableData = ref([]) |
|||
const dateRange = ref([]) |
|||
const searchObj = ref({ |
|||
name: '', |
|||
jwcode: '' |
|||
}) |
|||
const pagination = ref({ |
|||
pageNum: 1, |
|||
pageSize: 50, |
|||
total: 0 |
|||
}) |
|||
|
|||
//获取旧表数据 |
|||
const getOld = async function () { |
|||
if (findMenuById(menuTree.value, permissionMapping.History_Query)) { |
|||
try { |
|||
if ((searchObj.value.name || searchObj.value.jwcode) && activeName.value == 'old') { |
|||
const startTime = dateRange.value && dateRange.value[0] ? moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const endTime = dateRange.value && dateRange.value[1] ? moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const res = await API({ |
|||
url: '/history/getOldHistoryRecord', |
|||
data: { |
|||
...searchObj.value, |
|||
startTime: startTime, |
|||
endTime: endTime, |
|||
pageNum: pagination.value.pageNum, |
|||
pageSize: pagination.value.pageSize, |
|||
} |
|||
}) |
|||
if (res.code == 200) { |
|||
ElMessage.success('查询成功') |
|||
tableData.value = res.data.list |
|||
console.log('tableData.value', res.data.list); |
|||
pagination.value.total = res.data.total |
|||
} |
|||
} else { |
|||
ElMessage.error('请输入姓名或精网号') |
|||
return |
|||
} |
|||
} catch (e) { |
|||
ElMessage.error(e.message) |
|||
} |
|||
}); |
|||
|
|||
// 初始化逻辑 |
|||
onMounted(() => { |
|||
initPermissions() |
|||
console.log('============================',hasNew.value,hasOld.value) |
|||
if (route.name === 'history') { |
|||
const defaultRoute = getDefaultAuditRoute(); |
|||
navigateTo(defaultRoute); |
|||
} else { |
|||
// 非父路由初始化当前标签状态 |
|||
if (route.name === 'newHistory' || route.name === 'oldHistory') { |
|||
activeTab.value = route.name; |
|||
} |
|||
} |
|||
} |
|||
//获取新表数据 |
|||
const get = async function () { |
|||
if (findMenuById(menuTree.value, permissionMapping.History_Query)) { |
|||
try { |
|||
if ((searchObj.value.name || searchObj.value.jwcode) && activeName.value == 'new') { |
|||
const startTime = dateRange.value && dateRange.value[0] ? moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const endTime = dateRange.value && dateRange.value[1] ? moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const res = await API({ |
|||
url: '/history/getNewHistoryRecord', |
|||
data: { |
|||
...searchObj.value, |
|||
startTime: startTime, |
|||
endTime: endTime, |
|||
pageNum: pagination.value.pageNum, |
|||
pageSize: pagination.value.pageSize, |
|||
} |
|||
}) |
|||
if (res.code == 200) { |
|||
ElMessage.success('查询成功') |
|||
tableData.value = res.data.list |
|||
console.log('tableData.value', res.data.list) |
|||
pagination.value.total = res.data.total |
|||
} |
|||
} else { |
|||
ElMessage.error('请输入姓名或精网号') |
|||
return |
|||
} |
|||
} catch (e) { |
|||
ElMessage.error(e.message) |
|||
} |
|||
} |
|||
} |
|||
const resetSearch = function () { |
|||
searchObj.value = { |
|||
name: '', |
|||
jwcode: '' |
|||
} |
|||
dateRange.value = [] |
|||
} |
|||
const handlePageSizeChange = function (val) { |
|||
pagination.value.pageSize = val |
|||
if (activeName.value == 'new') { |
|||
get() |
|||
} else if (activeName.value == 'old') { |
|||
getOld() |
|||
} |
|||
} |
|||
const handleCurrentChange = function (val) { |
|||
pagination.value.pageNum = val |
|||
if (activeName.value == 'new') { |
|||
get() |
|||
} else if (activeName.value == 'old') { |
|||
getOld() |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
}); |
|||
</script> |
|||
<style> |
|||
</style> |
@ -0,0 +1,119 @@ |
|||
<template> |
|||
<el-card> |
|||
<el-text size="large">姓名:</el-text> |
|||
<el-input v-model="searchObj.name" placeholder="请输入姓名" style="width: 12vw;margin-right:1vw" |
|||
clearable></el-input> |
|||
|
|||
<el-text size="large">精网号:</el-text> |
|||
<el-input v-model="searchObj.jwcode" placeholder="请输入精网号" style="width: 12vw;margin-right:1vw" |
|||
clearable></el-input> |
|||
|
|||
<el-text size="large" style="width: 80px">更新时间:</el-text> |
|||
<el-date-picker v-model="dateRange" type="datetimerange" :default-time="defaultTime" range-separator="至" |
|||
start-placeholder="开始时间" end-placeholder="结束时间" style="width: 25vw;margin-right:1vw" /> |
|||
|
|||
<el-button type="success" @click="resetSearch">重置</el-button> |
|||
<el-button type="primary" @click="get">查询</el-button> |
|||
</el-card> |
|||
|
|||
<el-card style="margin-top:10px" v-show="tableData.length > 0"> |
|||
<el-table :data="tableData" style="width: 82vw;height:60vh"> |
|||
<el-table-column type="index" label="序号" width="100" header-align="center" align="center"> |
|||
<template #default="scope"> |
|||
{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="客户姓名" width="180" show-overflow-tooltip /> |
|||
<el-table-column prop="jwcode" label="精网号" width="180" header-align="center" align="center" /> |
|||
<el-table-column prop="num" label="数量" width="180" header-align="center" align="center" /> |
|||
<el-table-column prop="updateType" show-overflow-tooltip label="更新类型" width="180" align="center" /> |
|||
<el-table-column prop="freeGold" label="免费金币" width="180" align="center" /> |
|||
<el-table-column prop="permanentGold" label="永久金币" width="180" align="center" /> |
|||
<el-table-column prop="taskGold" label="任务金币" width="180" align="center" /> |
|||
<el-table-column prop="operator" label="操作人" width="180" /> |
|||
<el-table-column prop="createTime" label="更新时间" width="200" header-align="center" align="center" /> |
|||
<el-table-column prop="remark" label="备注" show-overflow-tooltip width="200" align="center" /> |
|||
</el-table> |
|||
<el-pagination background style="margin-top:20px" v-model:current-page="pagination.pageNum" |
|||
v-model:page-size="pagination.pageSize" layout="total, sizes, prev, pager, next, jumper" |
|||
:total="pagination.total" @size-change="handlePageSizeChange" |
|||
@current-change="handleCurrentChange"></el-pagination> |
|||
</el-card> |
|||
</template> |
|||
<script setup> |
|||
import { onMounted, ref } from 'vue' |
|||
import { ElMessage } from 'element-plus' |
|||
import API from '@/util/http.js' |
|||
import moment from 'moment' |
|||
import { useAdminStore } from "@/store/index.js" |
|||
import { storeToRefs } from "pinia" |
|||
import dayjs from 'dayjs' |
|||
const adminStore = useAdminStore() |
|||
const { adminData, menuTree } = storeToRefs(adminStore) |
|||
import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js" |
|||
const defaultTime = [ |
|||
new Date(2000, 1, 1, 0, 0, 0), |
|||
new Date(2000, 2, 1, 23, 59, 59), |
|||
] |
|||
|
|||
const tableData = ref([]) |
|||
const dateRange = ref([]) |
|||
const searchObj = ref({ |
|||
name: '', |
|||
jwcode: '' |
|||
}) |
|||
const pagination = ref({ |
|||
pageNum: 1, |
|||
pageSize: 50, |
|||
total: 0 |
|||
}) |
|||
//获取新表数据 |
|||
const get = async function () { |
|||
try { |
|||
if (searchObj.value.name || searchObj.value.jwcode) { |
|||
const startTime = dateRange.value && dateRange.value[0] ? moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const endTime = dateRange.value && dateRange.value[1] ? moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const res = await API({ |
|||
url: '/history/getNewHistoryRecord', |
|||
data: { |
|||
...searchObj.value, |
|||
startTime: startTime, |
|||
endTime: endTime, |
|||
pageNum: pagination.value.pageNum, |
|||
pageSize: pagination.value.pageSize, |
|||
} |
|||
}) |
|||
if (res.code == 200) { |
|||
ElMessage.success('查询成功') |
|||
tableData.value = res.data.list |
|||
console.log('tableData.value', res.data.list) |
|||
pagination.value.total = res.data.total |
|||
} |
|||
} else { |
|||
ElMessage.error('请输入姓名或精网号') |
|||
return |
|||
} |
|||
} catch (e) { |
|||
ElMessage.error(e.message) |
|||
} |
|||
} |
|||
|
|||
const resetSearch = function () { |
|||
searchObj.value = { |
|||
name: '', |
|||
jwcode: '' |
|||
} |
|||
dateRange.value = [] |
|||
} |
|||
const handlePageSizeChange = function (val) { |
|||
pagination.value.pageSize = val |
|||
get() |
|||
|
|||
} |
|||
const handleCurrentChange = function (val) { |
|||
pagination.value.pageNum = val |
|||
get() |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,117 @@ |
|||
<template> |
|||
<el-card> |
|||
<el-text size="large">姓名:</el-text> |
|||
<el-input v-model="searchObj.name" placeholder="请输入姓名" style="width: 12vw;margin-right:1vw" |
|||
clearable></el-input> |
|||
|
|||
<el-text size="large">精网号:</el-text> |
|||
<el-input v-model="searchObj.jwcode" placeholder="请输入精网号" style="width: 12vw;margin-right:1vw" |
|||
clearable></el-input> |
|||
|
|||
<el-text size="large" style="width: 80px">更新时间:</el-text> |
|||
<el-date-picker v-model="dateRange" type="datetimerange" :default-time="defaultTime" range-separator="至" |
|||
start-placeholder="开始时间" end-placeholder="结束时间" style="width: 25vw;margin-right:1vw" /> |
|||
|
|||
<el-button type="success" @click="resetSearch">重置</el-button> |
|||
<el-button type="primary" @click="getOld">查询</el-button> |
|||
</el-card> |
|||
|
|||
<el-card style="margin-top:10px" v-show="tableData.length > 0"> |
|||
<el-table :data="tableData" style="width: 82vw;height:60vh"> |
|||
<el-table-column type="index" label="序号" width="100" header-align="center" align="center"> |
|||
<template #default="scope"> |
|||
{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="客户姓名" width="180" show-overflow-tooltip /> |
|||
<el-table-column prop="jwcode" label="精网号" width="180" header-align="center" align="center" /> |
|||
<el-table-column prop="num" label="数量" width="180" header-align="center" align="center" /> |
|||
<el-table-column prop="updateType" show-overflow-tooltip label="更新类型" width="180" align="center" /> |
|||
<el-table-column prop="operator" label="操作人" width="180" /> |
|||
<el-table-column prop="createTime" label="更新时间" width="200" header-align="center" align="center" /> |
|||
<el-table-column prop="remark" label="备注" show-overflow-tooltip width="200" align="center" /> |
|||
</el-table> |
|||
<el-pagination background style="margin-top:20px" v-model:current-page="pagination.pageNum" |
|||
v-model:page-size="pagination.pageSize" layout="total, sizes, prev, pager, next, jumper" |
|||
:total="pagination.total" @size-change="handlePageSizeChange" |
|||
@current-change="handleCurrentChange"></el-pagination> |
|||
</el-card> |
|||
</template> |
|||
<script setup> |
|||
import { onMounted, ref } from 'vue' |
|||
import { ElMessage } from 'element-plus' |
|||
import API from '@/util/http.js' |
|||
import moment from 'moment' |
|||
import { useAdminStore } from "@/store/index.js" |
|||
import { storeToRefs } from "pinia" |
|||
import dayjs from 'dayjs' |
|||
const adminStore = useAdminStore() |
|||
const { adminData, menuTree } = storeToRefs(adminStore) |
|||
import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js" |
|||
const defaultTime = [ |
|||
new Date(2000, 1, 1, 0, 0, 0), |
|||
new Date(2000, 2, 1, 23, 59, 59), |
|||
] |
|||
|
|||
const tableData = ref([]) |
|||
const dateRange = ref([]) |
|||
const searchObj = ref({ |
|||
name: '', |
|||
jwcode: '' |
|||
}) |
|||
const pagination = ref({ |
|||
pageNum: 1, |
|||
pageSize: 50, |
|||
total: 0 |
|||
}) |
|||
|
|||
//获取旧表数据 |
|||
const getOld = async function () { |
|||
try { |
|||
if (searchObj.value.name || searchObj.value.jwcode) { |
|||
const startTime = dateRange.value && dateRange.value[0] ? moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const endTime = dateRange.value && dateRange.value[1] ? moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss') : "" |
|||
const res = await API({ |
|||
url: '/history/getOldHistoryRecord', |
|||
data: { |
|||
...searchObj.value, |
|||
startTime: startTime, |
|||
endTime: endTime, |
|||
pageNum: pagination.value.pageNum, |
|||
pageSize: pagination.value.pageSize, |
|||
} |
|||
}) |
|||
if (res.code == 200) { |
|||
ElMessage.success('查询成功') |
|||
tableData.value = res.data.list |
|||
console.log('tableData.value', res.data.list); |
|||
pagination.value.total = res.data.total |
|||
} |
|||
} else { |
|||
ElMessage.error('请输入姓名或精网号') |
|||
return |
|||
} |
|||
} catch (e) { |
|||
ElMessage.error(e.message) |
|||
} |
|||
} |
|||
|
|||
|
|||
const resetSearch = function () { |
|||
searchObj.value = { |
|||
name: '', |
|||
jwcode: '' |
|||
} |
|||
dateRange.value = [] |
|||
} |
|||
const handlePageSizeChange = function (val) { |
|||
pagination.value.pageSize = val |
|||
getOld() |
|||
} |
|||
const handleCurrentChange = function (val) { |
|||
pagination.value.pageNum = val |
|||
getOld() |
|||
} |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -1,726 +0,0 @@ |
|||
<script setup> |
|||
import {onMounted, reactive, ref, watch} from "vue"; |
|||
import {ElMessage} from "element-plus"; |
|||
import moment from "moment"; |
|||
import request from "@/util/http.js"; |
|||
import Cookies from 'js-cookie'; |
|||
import {useAdminStore} from "@/store/index.js"; |
|||
import {storeToRefs} from "pinia"; |
|||
import {WarnTriangleFilled} from "@element-plus/icons-vue"; |
|||
import dayjs from "dayjs"; |
|||
|
|||
const adminStore = useAdminStore(); |
|||
const { adminData, menuTree } = storeToRefs(adminStore); |
|||
|
|||
const addDisabled = ref(false); |
|||
|
|||
const user = ref({ |
|||
jwcode: null, |
|||
name: "", |
|||
market: "", |
|||
historySumGold: null, |
|||
historyPermanentGold: null, |
|||
historyFreeGold: null, |
|||
historyTaskGold: null, |
|||
rechargeNum: null, |
|||
consumeNum: null, |
|||
firstRecharge: "", |
|||
nowPermanentGold: null, |
|||
nowFreeJune: null, |
|||
nowTaskGold: null, |
|||
nowFreeDecember: null, |
|||
nowFreeGold: null, |
|||
nowSumGold: null |
|||
}); |
|||
|
|||
const addConsume = ref({ |
|||
jwcode: null, |
|||
goodsName: "金币退款", |
|||
sumGold: null, |
|||
freeGold: null, |
|||
permanentGold: null, |
|||
taskGold: null, |
|||
remark: "", |
|||
refundModel: null, |
|||
adminId: adminData.value.id, |
|||
adminName: adminData.value.adminName |
|||
}); |
|||
|
|||
const Ref = ref(null); |
|||
|
|||
const rules = reactive({ |
|||
jwcode: [ |
|||
{ required: true, message: "请输入精网号", trigger: "blur" }, |
|||
], |
|||
remark: [ |
|||
{ required: true, message: "请输入备注", trigger: "blur" }, |
|||
], |
|||
|
|||
permanentGold: [ |
|||
{ required: true, message: "请输入永久金币数", trigger: "blur" }, |
|||
{ |
|||
validator: (rule, value, callback) => { |
|||
if (value === null || value === undefined || !Number.isInteger(value) || value < 0) { |
|||
callback(new Error("永久金币必须为非负整数")); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}, |
|||
trigger: "blur" |
|||
} |
|||
], |
|||
freeGold: [ |
|||
{ required: true, message: "请输入免费金币数", trigger: "blur" }, |
|||
{ |
|||
validator: (rule, value, callback) => { |
|||
if (value === null || value === undefined || !Number.isInteger(value) || value < 0) { |
|||
callback(new Error("免费金币必须为非负整数")); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}, |
|||
trigger: "blur" |
|||
} |
|||
], |
|||
taskGold: [ |
|||
{ required: true, message: "请输入任务金币数", trigger: "blur" }, |
|||
{ |
|||
validator: (rule, value, callback) => { |
|||
if (value === null || value === undefined || !Number.isInteger(value) || value < 0) { |
|||
callback(new Error("任务金币必须为非负整数")); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}, |
|||
trigger: "blur" |
|||
} |
|||
], |
|||
sumGold: [ |
|||
{ |
|||
validator: (rule, value, callback) => { |
|||
if ((value || 0) <= 0) { |
|||
callback(new Error("三类金币总数必须大于0")); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}, |
|||
trigger: "blur" |
|||
} |
|||
] |
|||
}); |
|||
|
|||
// watch 三类金币变化,自动计算总和 |
|||
watch( |
|||
() => [addConsume.value.freeGold, addConsume.value.permanentGold, addConsume.value.taskGold], |
|||
([free, permanent, task]) => { |
|||
const sum = (parseInt(free) || 0) + (parseInt(permanent) || 0) + (parseInt(task) || 0); |
|||
addConsume.value.sumGold = sum; |
|||
}, |
|||
{ deep: true } |
|||
); |
|||
|
|||
// 提交前校验 sumGold > 0 |
|||
function validateInputToFreeGold() { |
|||
if (!user.value.jwcode) { |
|||
ElMessage.warning("请先查询用户信息"); |
|||
resetForm() |
|||
return false; |
|||
|
|||
} |
|||
|
|||
const { freeGold, permanentGold, taskGold, sumGold } = addConsume.value; |
|||
if(freeGold > user.value.nowFreeGold){ |
|||
ElMessage.warning("该用户免费金币不足,请重新输入!"); |
|||
addConsume.value.freeGold = null; |
|||
return |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// 提交前校验 sumGold > 0 |
|||
function validateInputToPermanentGold() { |
|||
if (!user.value.jwcode) { |
|||
ElMessage.warning("请先查询用户信息"); |
|||
resetForm() |
|||
return false; |
|||
|
|||
} |
|||
const { freeGold, permanentGold, taskGold, sumGold } = addConsume.value; |
|||
if(permanentGold > user.value.nowPermanentGold){ |
|||
ElMessage.warning("该用户永久金币不足,请重新输入!"); |
|||
addConsume.value.permanentGold = null; |
|||
return |
|||
|
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// 提交前校验 sumGold > 0 |
|||
function validateInputToTaskGold() { |
|||
if (!user.value.jwcode) { |
|||
ElMessage.warning("请先查询用户信息"); |
|||
resetForm() |
|||
return false; |
|||
|
|||
} |
|||
const { freeGold, permanentGold, taskGold, sumGold } = addConsume.value; |
|||
if(taskGold > user.value.nowTaskGold){ |
|||
ElMessage.warning("该用户任务金币不足,请重新输入!"); |
|||
addConsume.value.taskGold = null; |
|||
return |
|||
|
|||
} |
|||
|
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
// 提交前校验 sumGold > 0 |
|||
function validateInputTOSumGold() { |
|||
if (!user.value.jwcode) { |
|||
ElMessage.warning("请先查询用户信息"); |
|||
resetForm() |
|||
return false; |
|||
|
|||
} |
|||
const { freeGold, permanentGold, taskGold, sumGold } = addConsume.value; |
|||
|
|||
if (sumGold <= 0) { |
|||
ElMessage.warning("三类金币总数必须大于0"); |
|||
resetForm() |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// 充值对话框显示状态 |
|||
const ConsumeDialogVisible = ref(false); |
|||
|
|||
// 关闭对话框 |
|||
const ConsumeDialogVisiblehandleClose = () => { |
|||
ConsumeDialogVisible.value = false; |
|||
// 重置表单数据 |
|||
resetForm() |
|||
user.value = {} |
|||
}; |
|||
`` |
|||
// 确认使用cookie继续充值 |
|||
const ConsumeDialogVisibleContinue = () => { |
|||
ConsumeDialogVisible.value = false; |
|||
add(); |
|||
}; |
|||
|
|||
const ConsumeDialogVisibleCancel = () => { |
|||
ConsumeDialogVisible.value = false |
|||
resetForm() |
|||
user.value = {} |
|||
}; |
|||
|
|||
// 第一次弹窗 |
|||
// 充值对话框显示状态 |
|||
const FirstConsumeDialogVisible = ref(false); |
|||
|
|||
// 关闭对话框 |
|||
const FirstConsumeDialogVisiblehandleClose = () => { |
|||
FirstConsumeDialogVisible.value = false; |
|||
// 重置表单数据 |
|||
resetForm() |
|||
user.value = {} |
|||
}; |
|||
|
|||
// 第一次消耗 |
|||
const FirstConsumeDialogVisibleContinue = () => { |
|||
FirstConsumeDialogVisible.value = false; |
|||
add(); |
|||
}; |
|||
|
|||
const FirstConsumeDialogVisibleCancel = () => { |
|||
FirstConsumeDialogVisible.value = false |
|||
resetForm() |
|||
user.value = {} |
|||
}; |
|||
|
|||
// 查询商品列表 |
|||
const goods = ref([]); |
|||
|
|||
|
|||
// 用来写的 cookie 的 key |
|||
const WriteCookies = ref(null) |
|||
// 用来写的 cookie 的 value |
|||
const WriteCookiesTime = ref(null) |
|||
// 用来读的 cookie 的 key |
|||
const ReadCookies = ref(null) |
|||
// 用来读的 cookie 的 value |
|||
const ReadCookiesTime = ref(null) |
|||
|
|||
// 添加消费 |
|||
const add = async function () { |
|||
addDisabled.value = true; |
|||
|
|||
try { |
|||
const result = await request({ |
|||
url: "/consume/addRefund", |
|||
data: { |
|||
jwcode: addConsume.value.jwcode, |
|||
adminId: adminData.value.id, |
|||
sumGold: addConsume.value.sumGold *100 , |
|||
freeGold: addConsume.value.freeGold *100 , |
|||
taskGold: addConsume.value.taskGold *100 , |
|||
permanentGold: addConsume.value.permanentGold *100 , |
|||
remark: addConsume.value.remark, |
|||
adminName: adminData.value.adminName |
|||
} |
|||
}); |
|||
|
|||
//存一下 用户的jwcode |
|||
// 拼接 jwcode:permanentGold:freeGold |
|||
WriteCookies.value = `coinRefund:${addConsume.value.jwcode}:${addConsume.value.goodsName}` |
|||
//value 为当前消耗时间 |
|||
WriteCookiesTime.value = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
|||
// 设置cookies,用户jwcode为key,value也是jwcode,过期时间为1天 |
|||
Cookies.set(WriteCookies.value, WriteCookiesTime.value, { |
|||
expires: |
|||
1, path: '/' |
|||
}); |
|||
addDisabled.value = false; |
|||
|
|||
if (result.code === 200) { |
|||
ElMessage.success("添加成功"); |
|||
resetForm(); |
|||
} else { |
|||
ElMessage.error(result.msg || "添加失败"); |
|||
} |
|||
} catch (err) { |
|||
console.error(err); |
|||
ElMessage.error("添加失败,请检查网络"); |
|||
addDisabled.value = false; |
|||
} |
|||
}; |
|||
|
|||
// 重置表单 |
|||
function resetForm() { |
|||
Ref.value.resetFields(); |
|||
addConsume.value.sumGold = null; |
|||
addConsume.value.freeGold = null; |
|||
addConsume.value.permanentGold = null; |
|||
addConsume.value.taskGold = null; |
|||
addConsume.value.sumGold = null; |
|||
addConsume.value.remark = ""; |
|||
addConsume.value.jwcode = null; |
|||
|
|||
user.value = { |
|||
jwcode: null, |
|||
name: "", |
|||
market: "", |
|||
historySumGold: null, |
|||
historyPermanentGold: null, |
|||
historyFreeGold: null, |
|||
historyTaskGold: null, |
|||
rechargeNum: null, |
|||
consumeNum: null, |
|||
firstRecharge: "", |
|||
nowPermanentGold: null, |
|||
nowFreeJune: null, |
|||
nowTaskGold: null, |
|||
nowFreeDecember: null, |
|||
nowFreeGold: null, |
|||
nowSumGold: null |
|||
}; |
|||
} |
|||
|
|||
// 获取商品信息 |
|||
const getGoods = async function () { |
|||
try { |
|||
const result = await request({ url: "https://api.homilychart.com/live_mall/api/product/all" }); |
|||
goods.value = result.data.map(item => ({ id: item.id, label: item.name, value: item.name })); |
|||
} catch (err) { |
|||
console.error(err); |
|||
} |
|||
} |
|||
|
|||
// 添加前验证 |
|||
const addBefore = () => { |
|||
Ref.value.validate(async (valid) => { |
|||
// 验证cookie |
|||
if (!valid) { |
|||
ElMessage({ |
|||
type: 'error', |
|||
message: '请检查输入内容' |
|||
}); |
|||
return; |
|||
} |
|||
// 手动校验 sumGold > 0 |
|||
if (!validateInputTOSumGold()) return; |
|||
|
|||
ReadCookies.value = `coinRefund:${addConsume.value.jwcode}:${addConsume.value.goodsName}` |
|||
// 获取cookie |
|||
const cookie = Cookies.get(ReadCookies.value) |
|||
console.log("cookie++++++++++++++++++++++", cookie) |
|||
console.log("time", WriteCookiesTime.value) |
|||
// 格式化时间 |
|||
ReadCookiesTime.value = moment(cookie).format('YYYY-MM-DD HH:mm:ss') |
|||
console.log("cookie========", cookie) |
|||
if (cookie) { |
|||
ConsumeDialogVisible.value = true; |
|||
} else { |
|||
FirstConsumeDialogVisible.value = true; |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
// 查询用户 |
|||
const getUser = async function (jwcode) { |
|||
if (!jwcode || !/^\d{1,9}$/.test(jwcode)) { |
|||
ElMessage.warning("精网号不能为空或格式不正确"); |
|||
return; |
|||
} |
|||
|
|||
try { |
|||
const result = await request({ url: "/user/selectUser", data: { jwcode } }); |
|||
|
|||
if (result.code === 200 && result.data) { |
|||
user.value = { ...result.data }; |
|||
ElMessage.success("查询成功"); |
|||
} else { |
|||
ElMessage.warning(result.msg || "用户不存在"); |
|||
} |
|||
} catch (err) { |
|||
console.error(err); |
|||
ElMessage.error("查询失败,请检查网络或精网号"); |
|||
} |
|||
}; |
|||
|
|||
onMounted(async function () { |
|||
await getGoods(); |
|||
}); |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="father1"> |
|||
<div class="left"> |
|||
<el-form :model="addConsume" ref="Ref" :rules="rules" style="min-width: 420px;" class="add-form" |
|||
label-width="auto" label-position="right"> |
|||
<el-form-item prop="jwcode" label="精网号" style="margin-top: 50px"> |
|||
<el-input v-model="addConsume.jwcode" style="width: 200px;" /> |
|||
<el-button type="primary" @click="getUser(addConsume.jwcode)" style="margin-left: 20px">查询 |
|||
</el-button> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="goodsName" label="商品名称" > |
|||
<el-input v-model="addConsume.goodsName" disabled style="width: 120px" /> |
|||
</el-form-item> |
|||
|
|||
<!-- 三类金币可编辑 --> |
|||
<el-form-item prop="permanentGold" label="永久金币"> |
|||
<el-input v-model.number="addConsume.permanentGold" style="width: 120px" @input="validateInputToPermanentGold()"/> |
|||
<p> 个</p> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="freeGold" label="免费金币"> |
|||
<el-input v-model.number="addConsume.freeGold" style="width: 120px" @input="validateInputToFreeGold()" /> |
|||
<p> 个</p> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="taskGold" label="任务金币"> |
|||
<el-input v-model.number="addConsume.taskGold" style="width: 120px" @input="validateInputToTaskGold()" /> |
|||
<p> 个</p> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="sumGold" label="消耗金币总数"> |
|||
<el-input v-model.number="addConsume.sumGold" style="width: 120px" disabled /> |
|||
</el-form-item> |
|||
|
|||
<el-form-item prop="remark" label="备注"> |
|||
<el-input v-model="addConsume.remark" style="width: 250px" :rows="4" maxlength="100" show-word-limit |
|||
type="textarea" /> |
|||
</el-form-item> |
|||
|
|||
<el-button type="success" @click="resetForm()" style="margin-left: 200px;margin-top:10px">重置</el-button> |
|||
<el-button type="primary" :disabled="addDisabled" @click="addBefore" style="margin-top:10px"> 提交</el-button> |
|||
</el-form> |
|||
</div> |
|||
|
|||
<div class="right"> |
|||
<!-- 客户信息栏 --> |
|||
<el-card v-if="user.jwcode" style="width: 800px; float: right" class="customer-info"> |
|||
<el-form :model="user" label-width="auto" style="max-width: 1000px" label-position="left"> |
|||
<el-text size="large" style="margin-left: 20px">客户信息</el-text> |
|||
|
|||
<!-- 第一行:姓名 + 历史金币 --> |
|||
<el-row style="margin-top: 20px"> |
|||
<el-col :span="9"> |
|||
<el-form-item label="姓名"> |
|||
<p>{{ user.name }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<el-form-item label="当前金币总数" style="width: 500px"> |
|||
<span style="color: #2fa1ff; margin-right: 5px" v-if="user.nowSumGold !== undefined">{{ |
|||
user.nowSumGold |
|||
}}</span> |
|||
</el-form-item> |
|||
<!-- 金币详情独立显示 --> |
|||
<el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 --> |
|||
<span style="color: #b1b1b1; margin-left: 0px" v-if="user.nowPermanentGold !== undefined">(永久金币:{{ |
|||
user.nowPermanentGold |
|||
}}; |
|||
免费金币:{{ user.nowFreeGold }}; |
|||
任务金币:{{ user.nowTaskGold }})</span> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
<!-- 第二行:精网号 + 当前金币(独立行) --> |
|||
<el-row> |
|||
<el-col :span="9"> |
|||
<el-form-item label="精网号"> |
|||
<p>{{ user.jwcode }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="14"> |
|||
<el-form-item label="消费次数"> |
|||
<p style="color: #2fa1ff">{{ user.consumeNum }} </p> |
|||
</el-form-item> |
|||
<el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 --> |
|||
<p style="font-size: small; color: #b1b1b1">(仅统计2025-01-01后的数据)</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
<!-- 第三行:首次充值日期 + 充值次数 --> |
|||
<!-- <el-row > |
|||
<el-col :span="9"> |
|||
<el-form-item label="首次充值日期"> |
|||
<p v-if="user.firstRecharge"> |
|||
{{ moment(user.firstRecharge).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
|
|||
</el-row> --> |
|||
|
|||
<!-- 第四行:消费次数 + 所属门店 --> |
|||
<el-row> |
|||
<el-col :span="9"> |
|||
<el-form-item label="所属门店"> |
|||
<p>{{ user.market }}</p> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
</el-card> |
|||
|
|||
|
|||
<el-dialog v-model="FirstConsumeDialogVisible" title="操作确认" :before-close="FirstConsumeDialogVisiblehandleClose" |
|||
:close-on-click-modal="false" width="480px"> |
|||
<!-- 内容整体居中且收窄 --> |
|||
<div class="confirm-body"> |
|||
<!-- 用户信息 --> |
|||
<div> |
|||
<div class="field-label">用户信息</div> |
|||
<el-input :model-value="user.jwcode + (user.name ? '【' + user.name + '】' : '')" disabled /> |
|||
</div> |
|||
<!-- 活动名称 --> |
|||
<div class="field"> |
|||
<div class="field-label">商品名称</div> |
|||
<el-input v-model="addConsume.goodsName" disabled /> |
|||
</div> |
|||
<!--金币总数 --> |
|||
<div class="field"> |
|||
<div class="field-label">金币总数</div> |
|||
<el-input v-model="addConsume.sumGold" disabled /> |
|||
</div> |
|||
<!-- 金币详细信息(同一行左右排列) --> |
|||
<el-row :gutter="20" class="coins-row"> |
|||
<el-col :span="8"> |
|||
<div class="field"> |
|||
<div class="field-label">永久金币</div> |
|||
<el-input v-model="addConsume.permanentGold" disabled /> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div class="field"> |
|||
<div class="field-label">免费金币</div> |
|||
<el-input v-model="addConsume.freeGold" disabled /> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div class="field"> |
|||
<div class="field-label">任务金币</div> |
|||
<el-input v-model="addConsume.taskGold" disabled /> |
|||
</div> |
|||
</el-col> |
|||
|
|||
</el-row> |
|||
|
|||
<div class="field"> |
|||
<div class="field-label">备注</div> |
|||
<el-input v-model="addConsume.remark" disabled /> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 底部按钮(居中) --> |
|||
<template #footer> |
|||
<div class="dialog-footer-center"> |
|||
<el-button @click="FirstConsumeDialogVisibleCancel">取 消</el-button> |
|||
<el-button type="primary" @click="FirstConsumeDialogVisibleContinue">确认退款</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
|
|||
|
|||
<el-dialog v-model="ConsumeDialogVisible" title="操作确认" :before-close="ConsumeDialogVisiblehandleClose" |
|||
:close-on-click-modal="false" width="480px"> |
|||
<!-- 内容整体居中且收窄 --> |
|||
<div class="confirm-body"> |
|||
<!-- 用户信息 --> |
|||
<div> |
|||
<div class="field-label">用户信息</div> |
|||
<el-input :model-value="user.jwcode + (user.name ? '【' + user.name + '】' : '')" disabled /> |
|||
</div> |
|||
<!-- 活动名称 --> |
|||
<div class="field"> |
|||
<div class="field-label">商品名称</div> |
|||
<el-input v-model="addConsume.goodsName" disabled /> |
|||
</div> |
|||
<!--金币总数 --> |
|||
<div class="field"> |
|||
<div class="field-label">金币总数</div> |
|||
<el-input v-model="addConsume.sumGold" disabled /> |
|||
</div> |
|||
<!-- 金币详细信息(同一行左右排列) --> |
|||
<el-row :gutter="20" class="coins-row"> |
|||
<el-col :span="8"> |
|||
<div class="field"> |
|||
<div class="field-label">永久金币</div> |
|||
<el-input v-model="addConsume.permanentGold" disabled /> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div class="field"> |
|||
<div class="field-label">免费金币</div> |
|||
<el-input v-model="addConsume.freeGold" disabled /> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div class="field"> |
|||
<div class="field-label">任务金币</div> |
|||
<el-input v-model="addConsume.taskGold" disabled /> |
|||
</div> |
|||
</el-col> |
|||
|
|||
</el-row> |
|||
<!-- 风险提示 --> |
|||
<div style="display: flex; align-items: center; margin-top: 20px;"> |
|||
<el-icon :size="24" color="#FFD700"> |
|||
<WarnTriangleFilled /> |
|||
</el-icon> |
|||
<p>重复购买风险提示</p> |
|||
</div> |
|||
<!-- 记录 + 虚线分隔 --> |
|||
<div> |
|||
<el-divider border-style="dashed" /> |
|||
<p>检测到该用户近期有相似退款记录:</p> |
|||
· {{ ReadCookiesTime }} 退款 【{{ addConsume.goodsName }}】(操作人: {{ adminData.adminName }}) |
|||
</div> |
|||
<div style="margin-top: 10px"> |
|||
<p>是否继续操作?</p> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 底部按钮(居中) --> |
|||
<template #footer> |
|||
<div class="dialog-footer-center"> |
|||
<el-button @click="ConsumeDialogVisibleCancel">取 消</el-button> |
|||
<el-button type="primary" @click="ConsumeDialogVisibleContinue">确认退款</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
|
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
|
|||
<style scoped lang="scss"> |
|||
p { |
|||
margin: 0px; |
|||
} |
|||
|
|||
/* 上传图片的格式 */ |
|||
.avatar-uploader .avatar { |
|||
width: 50px; |
|||
height: 50px; |
|||
display: block; |
|||
} |
|||
|
|||
.add-form { |
|||
width: 400px; |
|||
float: left; |
|||
} |
|||
|
|||
/* 标题居中 */ |
|||
.el-dialog__header { |
|||
text-align: center; |
|||
} |
|||
|
|||
.confirm-body { |
|||
width: 350px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
/* 字段块与标签样式 */ |
|||
.field { |
|||
margin-bottom: 14px; |
|||
} |
|||
|
|||
.field-label { |
|||
font-size: 14px; |
|||
color: #606266; |
|||
margin-bottom: 6px; |
|||
} |
|||
|
|||
/* 金币行紧凑 */ |
|||
.coins-row .field { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
/* 底部按钮居中 */ |
|||
.dialog-footer-center { |
|||
display: flex; |
|||
justify-content: center; |
|||
gap: 12px; |
|||
} |
|||
|
|||
.father1 { |
|||
width: 82vw; |
|||
height: 80vh; |
|||
display: flex; |
|||
|
|||
.left { |
|||
width: 500px; |
|||
float: left; |
|||
display: flex; |
|||
} |
|||
|
|||
.right { |
|||
flex: 1; |
|||
height: 50vh; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.customer-info { |
|||
width: 300px; |
|||
margin-left: 20px; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
} |
|||
} |
|||
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue