This commit is contained in:
2023-09-13 18:29:35 +08:00
commit 4ac8391a9a
126 changed files with 15555 additions and 0 deletions

View File

@@ -0,0 +1,347 @@
<template>
<div class="card">
<el-space>
<el-button type="primary" icon="Plus" @click="addHandle">添加菜单</el-button>
</el-space>
<div class="mt15">
<el-space>
<el-select placeholder="请选择分组" v-model="tableOptions.navcode">
<el-option :value="item.id" :label="item.name" v-for="item in menuGroups" :key="item.id"></el-option>
</el-select>
<el-select placeholder="请选择导航" v-model="tableOptions.navName">
<el-option :value="item.id" :label="item.name" v-for="item in navcodes" :key="item.id"></el-option>
</el-select>
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
<el-button icon="RefreshRight" @click="resizeTable">重置</el-button>
</el-space>
</div>
<div class="table mt15">
<el-table ref="table" :data="tableOptions.list" border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column label="图标" width="100">
<template #default="scope">
<el-image style="width: 50px; height: 50px" :src="scope.row.icon" preview-teleported
hide-on-click-modal :preview-src-list="[scope.row.icon]" fit="cover">
</el-image>
</template>
</el-table-column>
<el-table-column prop="menuGroup" label="分组">
<template #default="scope">
<el-text>{{ menuGroups.find(item => item.id == scope.row.menuGroup).name }}</el-text>
</template>
</el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="navName" label="导航"></el-table-column>
<el-table-column prop="url" label="链接"></el-table-column>
<el-table-column label="是否显示" width="100">
<template #default="scope">
<el-text v-if="scope.row.visible == 0" type="info">不显示</el-text>
<el-text v-if="scope.row.visible == 1" type="primary">显示</el-text>
</template>
</el-table-column>
<el-table-column label="是否小程序" width="100">
<template #default="scope">
<el-text v-if="scope.row.isapplets == 0" type="info"></el-text>
<el-text v-if="scope.row.isapplets == 1" type="primary"></el-text>
</template>
</el-table-column>
<el-table-column label="是否uniapp" width="100">
<template #default="scope">
<el-text v-if="scope.row.isuniapp == 0" type="info"></el-text>
<el-text v-if="scope.row.isuniapp == 1" type="primary"></el-text>
</template>
</el-table-column>
<el-table-column label="显示(安卓/iso)" width="100">
<template #default="scope">
<el-text v-if="scope.row.isandroidenabled == 0" type="info"></el-text>
<el-text v-if="scope.row.isandroidenabled == 1" type="primary"></el-text>
<el-text type="info">/</el-text>
<el-text v-if="scope.row.isiphoneenabled == 0" type="info"></el-text>
<el-text v-if="scope.row.isiphoneenabled == 1" type="primary"></el-text>
</template>
</el-table-column>
<el-table-column prop="username" label="小程序ID"></el-table-column>
<el-table-column prop="path" label="跳转路径/uniApp路径"></el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间">
<template #default="scope">
{{ dayjs(scope.row.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="140">
<template #default="scope">
<el-button type="primary" size="small" icon="EditPen">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
<el-dialog title="增加菜单" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item prop="name" label="菜单名称">
<el-input placeholder="请输入菜单名称" v-model="form.name" />
</el-form-item>
<el-form-item prop="code" label="菜单code">
<el-input placeholder="请输入菜单code" v-model="form.code" />
</el-form-item>
<el-form-item prop="sort" label="排序">
<el-input placeholder="请输入菜单排序" v-model="form.sort" />
</el-form-item>
<el-form-item prop="url" label="图片url">
<el-upload ref="uploadRef" v-model:file-list="fileList" :limit="1" :on-exceed="handleExceed"
list-type="picture" :auto-upload="false" @change="selectFile" @remove="removeFile">
<template #trigger>
<el-button type="primary" icon="Picture">选择图片</el-button>
</template>
</el-upload>
</el-form-item>
<el-form-item prop="navcode" label="导航">
<el-select v-model="form.navcode">
<el-option :label="item.name" :value="item.id" v-for="item in navcodes" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="menuGroup" label="分组">
<el-select v-model="form.menuGroup">
<el-option :label="item.name" :value="item.id" v-for="item in menuGroups" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="type" label="是否显示">
<el-radio-group v-model="form.visible">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="type" label="安卓是否显示">
<el-radio-group v-model="form.isAndroidEnabled">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="type" label="ios是否显示">
<el-radio-group v-model="form.isIphoneEnabled">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
</template>
<script setup>
import { dayjs } from 'element-plus';
import { appMenuPage, getDictGroup, uploadOSS, appMenuSave } from '@/api/home.js'
import { onMounted, reactive } from 'vue';
const table = ref(null)
const navcodes = ref([])
const menuGroups = ref([])
// 表格参数
const tableOptions = reactive({
loading: true,
navcode: '',
navName: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 添加菜单
function addHandle() {
showDialog.value = true
}
// 重置表格
function resizeTable() {
tableOptions.navcode = ''
tableOptions.navName = ''
searchHandle()
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
appMenuPageAjax()
}
// app菜单list
async function appMenuPageAjax() {
try {
const res = await appMenuPage({
page: tableOptions.pageNum,
size: tableOptions.pageSzie
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
table.value.setScrollTop(0)
} catch (error) { }
}
// 获取分组字典值
async function getMenuGrounp() {
try {
const res = await getDictGroup('APP_MENU_GROUP')
menuGroups.value = res
} catch (error) { }
}
// 获取导航字典值
async function getNavCodes() {
try {
const res = await getDictGroup('APP_MENU_NAV')
navcodes.value = res
} catch (error) { }
}
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const formRef = ref(null)
const fileList = ref([])
// 创建表单
const form = reactive({
name: '', // 菜单名称
code: '', // 菜单code
sort: '', // 排序
url: '', // 图标
navcode: '', // 导航选择
menuGroup: '', // 分组
visible: 1, // 是否显示0否1是
isAndroidEnabled: 1, // 安卓是否显示
isIphoneEnabled: 1, // ios是否显示
})
// 校验是否选择图片
const imgValidate = (rule, value, callback) => {
if (fileList.value.length <= 0) {
return callback(new Error('请选择图片'))
} else {
callback()
}
}
// 表单校验规则
const rules = reactive({
name: [
{
required: true,
message: '',
trigger: 'blur'
}
],
code: [
{
required: true,
message: '',
trigger: 'blur'
}
],
sort: [
{
required: true,
message: '',
trigger: 'blur'
}
],
url: [
{
required: true,
validator: imgValidate,
trigger: 'change'
}
],
navcode: [
{
required: true,
message: '',
trigger: 'change'
}
],
menuGroup: [
{
required: true,
message: '',
trigger: 'change'
}
]
})
// 只能选择一个文件,替换之前的文件
const handleExceed = (files) => {
uploadRef.value.clearFiles()
const file = files[0]
file.uid = genFileId()
uploadRef.value.handleStart(file)
form.url = ''
}
// 选择图片
const selectFile = async (file) => {
fileList.value = [file]
}
// 移除图片
const removeFile = async () => {
fileList.value = []
form.url = ''
}
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
fileList.value = []
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild) => {
if (vaild) {
try {
formLoading.value = true
form.url = await uploadOSS(fileList.value[0].raw)
await appMenuSave(form)
formLoading.value = false
showDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
onMounted(async () => {
await getMenuGrounp()
await getNavCodes()
await appMenuPageAjax()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 356px);
}
</style>

12
src/views/demo/demo11.vue Normal file
View File

@@ -0,0 +1,12 @@
<template>
<div class="demo">
<h2>demo11</h2>
</div>
</template>
<script setup>
let aa = ref('')
</script>
<style lang="scss" scoped></style>

12
src/views/demo/demo12.vue Normal file
View File

@@ -0,0 +1,12 @@
<template>
<div class="demo">
<h2>demo12</h2>
<router-view></router-view>
</div>
</template>
<script setup>
let aa = ref("");
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,11 @@
<template>
<div class="demo">
<h2>demo121</h2>
</div>
</template>
<script setup>
let aa = ref("");
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,9 @@
<template>
<div class="demo">
<h2>demo122</h2>
</div>
</template>
<script setup></script>
<style lang="scss" scoped></style>

12
src/views/demo/demo13.vue Normal file
View File

@@ -0,0 +1,12 @@
<template>
<div class="demo">
<h2>demo13</h2>
</div>
</template>
<script setup>
let aa = ref('')
</script>
<style lang="scss" scoped></style>

11
src/views/demo/demo21.vue Normal file
View File

@@ -0,0 +1,11 @@
<template>
<div class="demo">
<h2>demo21</h2>
</div>
</template>
<script setup>
let aa = ref('')
</script>
<style lang="scss" scoped></style>

11
src/views/demo/demo22.vue Normal file
View File

@@ -0,0 +1,11 @@
<template>
<div class="demo">
<h2>demo22</h2>
</div>
</template>
<script setup>
let aa = ref('')
</script>
<style lang="scss" scoped></style>

11
src/views/demo/demo23.vue Normal file
View File

@@ -0,0 +1,11 @@
<template>
<div class="demo">
<h2>demo23</h2>
</div>
</template>
<script setup>
let aa = ref('')
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,200 @@
<template>
<div class="card">
<div class="data_row">
<div class="item">
<div class="icon">
<img class="img" src="@/assets/icon_dev1.png">
</div>
<div class="info">
<div class="title">总设备数</div>
<div class="num">
<count-to :start-val="0" :end-val="deviceData.sumCount" :duration="1000" />
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="@/assets/icon_dev2.png">
</div>
<div class="info">
<div class="title">已激活数</div>
<div class="num">
<count-to :start-val="0" :end-val="deviceData.activityCount" :duration="1000" />
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="@/assets/icon_dev3.png">
</div>
<div class="info">
<div class="title">未激活数</div>
<div class="num">
<count-to :start-val="0" :end-val="deviceData.sellCount" :duration="1000" />
</div>
</div>
</div>
</div>
</div>
<div class="card mt15">
<el-space class="pb15">
<el-input placeholder="请输入商户编号搜索" v-model="tableOptions.merchantCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table">
<el-table :data="tableOptions.list" size="large" stripe border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="merchantCode" label="商户号"></el-table-column>
<el-table-column prop="snNo" label="设备号"></el-table-column>
<el-table-column prop="actMercName" label="商户名"></el-table-column>
<el-table-column prop="phone" label="联系电话"></el-table-column>
<el-table-column prop="status" label="激活状态">
<template #default="scope">
<el-tag type="success" disable-transitions v-if="scope.row.status == 3">已激活</el-tag>
<el-tag type="warning" disable-transitions v-else>未激活</el-tag>
</template>
</el-table-column>
<el-table-column prop="countSum" label="收单笔数"></el-table-column>
<el-table-column prop="consumeFee" label="收单总额"></el-table-column>
<el-table-column prop="loginName" label="上级名称"></el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
</template>
<script setup>
import { onMounted, reactive } from 'vue';
import { getSumDeviceStock, getDeviceStockInfo } from '@/api/device.js'
const deviceData = reactive({
sumCount: 0,
activityCount: 0,
sellCount: 0
})
// 表格参数
const tableOptions = reactive({
loading: true,
merchantCode: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
getDeviceStockInfoHandle()
}
// 获取当前用户设备总数
async function getSumDeviceStockHandle() {
try {
const { sumCount, activityCount, sellCount } = await getSumDeviceStock()
deviceData.sumCount = sumCount
deviceData.activityCount = activityCount
deviceData.sellCount = sellCount
} catch (error) { }
}
// 获取设备列表
async function getDeviceStockInfoHandle() {
try {
const { total, list } = await getDeviceStockInfo({
merchantCode: tableOptions.merchantCode,
pageNum: tableOptions.pageNum,
pageSize: tableOptions.pageSzie
})
tableOptions.loading = false
tableOptions.total = total
tableOptions.list = list
} catch (error) {
tableOptions.loading = false
}
}
onMounted(() => {
getSumDeviceStockHandle()
getDeviceStockInfoHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 456px);
}
.data_row {
display: flex;
padding: 24px 0;
.item {
flex: 1;
display: flex;
padding-left: 50px;
&:not(:last-child) {
position: relative;
&::after {
content: "";
height: 100%;
border-right: 1px solid #ececec;
position: absolute;
top: 0;
right: 0;
}
}
.icon {
$size: 50px;
width: $size;
height: $size;
.img {
width: $size;
height: $size;
}
}
.info {
flex: 1;
padding-left: 20px;
display: flex;
flex-direction: column;
justify-content: center;
.title {
font-size: 14px;
color: #666;
font-weight: 300;
}
.num {
font-size: 24px;
font-weight: bold;
padding-top: 10px;
.i {
font-size: 12px;
position: relative;
bottom: 1px;
right: -4px;
}
}
}
}
}
</style>

10
src/views/error/401.vue Normal file
View File

@@ -0,0 +1,10 @@
<template>
<div class="401">
<h1>401</h1>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped></style>

44
src/views/error/404.vue Normal file
View File

@@ -0,0 +1,44 @@
<template>
<div class="empty-404">
<img src="../../assets/images/404.png">
<p class="tips">您访问的页面不存在</p>
<el-button @click="goRoute">{{ countDown }}s 返回</el-button>
</div>
</template>
<script setup>
const router = useRouter()
function goRoute() {
router.push('/home');
}
let countDown = ref(5)
let timer = setInterval(() => {
countDown.value--
if (countDown.value == 0) {
goRoute()
}
}, 1000)
onUnmounted(() => {
clearInterval(timer)
})
</script>
<style lang="scss" scoped>
.empty-404 {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.tips {
font-size: 40px;
line-height: 100px;
}
}
</style>

215
src/views/home.vue Normal file
View File

@@ -0,0 +1,215 @@
<template>
<div class="card">
<div class="header_title">
欢迎回来{{ storeUser.userInfo.loginName }}
</div>
<div class="data_row">
<div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon1.png">
</div>
<div class="info">
<div class="title">团队总流水</div>
<div class="num">
<count-to :start-val="0" :decimals="2" :end-val="homeData.sumConsumeFee" :duration="1000" />
<!-- {{ homeData.sumConsumeFee }} -->
<span class="i"></span>
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon2.png">
</div>
<div class="info">
<div class="title">总收益</div>
<div class="num">
<count-to :start-val="0" :decimals="2" :end-val="homeData.sumfansShareMoney" :duration="1000" />
<span class="i"></span>
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon3.png">
</div>
<div class="info">
<div class="title">今日收益</div>
<div class="num">
<count-to :start-val="0" :decimals="2" :end-val="homeData.yestedayShareMoney" :duration="1000" />
<span class="i"></span>
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon4.png">
</div>
<div class="info">
<div class="title">推广费率</div>
<div class="num">
{{ homeData.currentFee }}
<span class="i">%</span>
</div>
</div>
</div>
</div>
</div>
<div class="card mt15">
<chart-card :user-id="storeUser.userInfo.userId" />
</div>
</template>
<script setup>
import { getIndexData } from '@/api/home.js'
import { useUser } from "@/store/user.js";
import chartCard from '@/components/chartCard.vue';
const storeUser = useUser();
let homeData = reactive({
sumConsumeFee: 0,
sumfansShareMoney: 0,
yestedayShareMoney: 0,
currentFee: 0
})
// 获取首页数据
async function getIndexDataHandle() {
try {
const res = await getIndexData()
homeData.sumConsumeFee = res.sumConsumeFee
homeData.sumfansShareMoney = res.sumfansShareMoney
homeData.yestedayShareMoney = res.yestedayShareMoney
homeData.currentFee = res.currentFee
} catch (error) {
console.log(error)
}
}
onMounted(() => {
getIndexDataHandle()
});
</script>
<style lang="scss" scoped>
.header_title {
font-size: 18px;
font-weight: bold;
padding: 15px 0 30px 0;
border-bottom: 1px solid #ececec;
}
.data_row {
display: flex;
padding: 50px 0;
.item {
flex: 1;
display: flex;
padding-left: 50px;
&:not(:last-child) {
position: relative;
&::after {
content: "";
height: 100%;
border-right: 1px solid #ececec;
position: absolute;
top: 0;
right: 0;
}
}
.icon {
$size: 55px;
width: $size;
height: $size;
border-radius: 50%;
background-color: #F2F3F5;
display: flex;
justify-content: center;
align-items: center;
.img {
$size: 30px;
width: $size;
height: $size;
object-fit: contain;
}
}
.info {
flex: 1;
padding-left: 20px;
display: flex;
flex-direction: column;
justify-content: center;
.title {
font-size: 14px;
color: #666;
font-weight: 300;
}
.num {
font-size: 24px;
font-weight: bold;
padding-top: 10px;
.i {
font-size: 12px;
position: relative;
bottom: 1px;
right: -4px;
}
}
}
}
}
.userInfo {
padding: 20px;
width: 100%;
display: flex;
align-items: center;
gap: 0 20px;
border: 1px solid #eee;
background-color: #fff;
.name {
font-size: 20px;
font-weight: 600;
}
}
.charts-case {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: repeat(2, 1fr);
gap: 10px;
grid-template-areas:
"a b"
"c c";
margin-top: 10px;
}
.charts-chunk {
border: 1px solid #eee;
background-color: #fff;
}
.charts-chunk:nth-child(0) {
grid-area: a;
}
.charts-chunk:nth-child(1) {
grid-area: b;
}
.charts-chunk:last-child {
grid-area: c;
}
</style>

View File

@@ -0,0 +1,3 @@
<template>
<router-view></router-view>
</template>

View File

@@ -0,0 +1,219 @@
<template>
<el-drawer class="vab-drawer" size="400px" :model-value="props.modelValue" :before-close="close">
<template #header>
<h4>配置</h4>
</template>
<template #default>
<el-divider>
<span>布局切换</span>
</el-divider>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 布局 </el-col>
<el-col :span="15">
<el-select v-model="getConfigure.menuMode" placeholder="请选择布局" @change="changeMenuMode(getConfigure.menuMode)">
<el-option v-for="(item, index) in layoutModeEnum.key" :key="item" :label="layoutModeEnum.value[index]" :value="item" />
</el-select>
</el-col>
</el-row>
<el-divider>
<span>主题配置</span>
</el-divider>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 主题色 </el-col>
<el-col :span="15">
<el-color-picker v-model="getConfigure.themeColor" @change="setConfigure('themeColor')" />
</el-col>
</el-row>
<el-divider>
<span>标签</span>
</el-divider>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 标签风格 </el-col>
<el-col :span="15">
<el-select v-model="getConfigure.navbarMode" placeholder="请选择布局">
<el-option v-for="(item, index) in navbarModeEnum.key" :key="item" :label="navbarModeEnum.value[index]" :value="item" />
</el-select>
</el-col>
</el-row>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 标签图标 </el-col>
<el-col :span="15">
<el-switch v-model="getConfigure.navbarIcon" />
</el-col>
</el-row>
<el-divider>
<span>菜单</span>
</el-divider>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 菜单背景 </el-col>
<el-col :span="15">
<el-color-picker v-if="getConfigure.menuMode == layoutModeEnum.key[0]" v-model="getConfigure.menuBGColor" @change="setConfigure('menuBGColor')" />
<el-color-picker v-else-if="getConfigure.menuMode == layoutModeEnum.key[1]" v-model="getConfigure.columnBgColor" @change="setConfigure('columnBgColor')" />
</el-col>
</el-row>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 菜单文字颜色 </el-col>
<el-col :span="15">
<el-color-picker v-model="getConfigure.textColor" @change="setConfigure('textColor')" />
</el-col>
</el-row>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title"> 菜单活跃文字颜色 </el-col>
<el-col :span="15">
<el-color-picker v-model="getConfigure.activeTextColor" @change="setConfigure('activeTextColor')" />
</el-col>
</el-row>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title">菜单的 Logo</el-col>
<el-col :span="15">
<el-switch v-model="getConfigure.showMenuLogo" />
</el-col>
</el-row>
<el-divider>
<span>过度</span>
</el-divider>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title">
组件切换过度
<el-tooltip class="box-item" effect="dark" content="开启组件切换过渡时,组件只能有一个根元素。" placement="top">
<SvgIcon name="QuestionFilled" color="#909399" style="margin-left: 5px"></SvgIcon>
</el-tooltip>
</el-col>
<el-col :span="15">
<el-switch v-model="getConfigure.componentTransition" />
</el-col>
</el-row>
<el-row :gutter="10" class="vab-row">
<el-col :span="9" class="list-title">组件过渡</el-col>
<el-col :span="15">
<el-select v-model="getConfigure.componentTransitionMode" placeholder="请选择过度模式">
<el-option v-for="(item, index) in componentTransitionEnum.key" :key="item" :label="componentTransitionEnum.value[index]" :value="item" />
</el-select>
</el-col>
</el-row>
</template>
<template #footer>
<div style="flex: auto">
<el-button type="primary" @click="confirm">保存</el-button>
<el-button @click="recovery">恢复默认</el-button>
</div>
</template>
</el-drawer>
</template>
<script setup>
import { useConfigure } from "@/store/configure.js";
// 控制组件的显示
const props = defineProps({
modelValue: {
type: Boolean,
required: true,
},
});
const emits = defineEmits(["update:modelValue"]);
function close() {
emits("update:modelValue", !props.modelValue);
}
// 获取配置
const storeConfigure = useConfigure();
const { configure } = storeToRefs(storeConfigure);
const getConfigure = computed(() => {
return configure.value;
});
// 获取枚举值
const { layoutModeEnum, navbarModeEnum, setColorEnum, componentTransitionEnum } = ENUMS;
// 切换侧边导航的布局
function changeMenuMode(mode) {
switch (mode) {
case layoutModeEnum.key[0]:
_hook.useCssVar("--el-menu-bg-color", storeConfigure.configure.menuBGColor);
break;
case layoutModeEnum.key[1]:
_hook.useCssVar("--el-menu-bg-color", "#ffffff");
break;
default:
}
}
// 设置配置
function setConfigure(type) {
_hook.useCssVar(setColorEnum[type], getConfigure.value[type]);
switch (type) {
case "themeColor":
_hook.useCssVar("--el-menu-hover-bg-color", storeConfigure.configure.themeColor);
[3, 5, 7, 8, 9].forEach((i) => {
_hook.useCssVar(`--el-color-primary-light-${i}`, _hook.useLightColor(getConfigure.value[type], `0.${i}`));
});
break;
case "menuBGColor":
storeConfigure.change("columnBgColor", storeConfigure.configure.menuBGColor);
_hook.useCssVar("--admin-column-bg-color", storeConfigure.configure.menuBGColor);
break;
case "columnBgColor":
storeConfigure.change("menuBGColor", storeConfigure.configure.columnBgColor);
break;
case "activeTextColor":
_hook.useCssVar("--el-menu-hover-text-color", storeConfigure.configure.activeTextColor);
break;
default:
}
}
// 保存配置
function confirm() {
_hook.useLocalStorage.set("configure", storeConfigure.configure);
ElMessage({
message: "配置保存成功",
type: "success",
});
}
// 恢复默认
function recovery() {
_hook.useLocalStorage.remove("configure");
storeConfigure.$reset();
// 初始化颜色
_hook.useCssVar("--el-color-primary", storeConfigure.configure.themeColor);
switch (storeConfigure.configure.menuMode) {
case layoutModeEnum.key[0]:
_hook.useCssVar("--el-menu-bg-color", storeConfigure.configure.menuBGColor);
break;
case layoutModeEnum.key[1]:
_hook.useCssVar("--el-menu-bg-color", "#ffffff");
break;
default:
}
_hook.useCssVar("--admin-column-bg-color", storeConfigure.configure.menuBGColor);
_hook.useCssVar("--el-menu-text-color", storeConfigure.configure.textColor);
_hook.useCssVar("--el-menu-active-color", storeConfigure.configure.activeTextColor);
[3, 5, 7, 8, 9].forEach((i) => {
_hook.useCssVar(`--el-color-primary-light-${i}`, _hook.useLightColor(storeConfigure.configure.themeColor, `0.${i}`));
});
ElMessage({
message: "配置已恢复默认",
type: "success",
});
}
</script>
<style lang="scss" scoped>
.vab-row {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.list-title {
display: flex;
align-items: center;
font-size: 15px;
line-height: 1;
color: --el-text-color-secondary;
}
</style>

View File

@@ -0,0 +1,121 @@
<template>
<div class="navbar-case">
<Transition name="navbar" mode="out-in">
<navbar-mode-a v-if="configure.navbarMode == navbarModeEnum.key[0]"></navbar-mode-a>
<navbar-mode-b v-else-if="configure.navbarMode == navbarModeEnum.key[1]"></navbar-mode-b>
<navbar-mode-c v-else-if="configure.navbarMode == navbarModeEnum.key[2]"></navbar-mode-c>
</Transition>
<div class="menu">
<el-dropdown @visible-change="changeDropdownVisible">
<div class="flex align-center" style="gap: 0 10px">
<SvgIcon class="menu-icon" :style="menuIconStyle" name="Menu"></SvgIcon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in menuItem" :key="item.title" @click="setNavList(item.type)">
<SvgIcon :name="item.icon"></SvgIcon>
<span>{{ item.title }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script setup>
import navbarModeA from "./navbar-modeA.vue";
import navbarModeB from "./navbar-modeB.vue";
import navbarModeC from "./navbar-modeC.vue";
import { useConfigure } from "@/store/configure.js";
import { useRoutes } from "@/store/routes.js";
const storeRoutes = useRoutes();
// 获取枚举值
const { navbarModeEnum } = ENUMS;
// 获取配置
const storeConfigure = useConfigure();
const { configure } = storeToRefs(storeConfigure);
// 下拉菜单
let menuItem = [
{
title: "关闭其他",
icon: "Close",
type: "else",
},
{
title: "关闭左侧",
icon: "Back",
type: "left",
},
{
title: "关闭右侧",
icon: "Right",
type: "right",
},
{
title: "关闭全部",
icon: "Close",
type: "all",
},
];
let menuIconStyle = reactive({
transform: `rotate(0deg)`,
color: "",
});
/**
* @description: 下拉菜单的显示与隐藏
* @param {Bool} bool: true显示 false隐藏
*/
function changeDropdownVisible(bool) {
menuIconStyle.transform = bool ? "rotate(45deg)" : "rotate(0deg)";
menuIconStyle.color = bool ? storeConfigure.configure.themeColor : "";
}
// 设置 nav 的列表
const router = useRouter();
function setNavList(type) {
storeRoutes.setNavList(type).then(() => {
router.push("/");
});
}
</script>
<style lang="scss" scoped>
// 导航栏动画
.navbar-enter-active,
.navbar-leave-active {
transition: opacity 0.3s ease;
}
.navbar-enter-from,
.navbar-leave-to {
opacity: 0;
}
.navbar-case {
display: flex;
align-items: center;
justify-content: space-between;
background-color: var(--el-color-info-light-9);
}
.menu {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
// background-color: var(--el-bg-color);
width: 50px;
height: 50px;
.menu-icon {
font-size: 20px;
color: var(--el-text-color-secondary);
transition: all 0.3s;
}
}
</style>

View File

@@ -0,0 +1,169 @@
<template>
<div class="navBar-list-mode-a">
<div :class="[storeRoutes.activeRoute == item[0] ? 'list-active' : 'list']" @click="goRoute(item[0])"
v-for="item in storeRoutes.navList">
<SvgIcon class="list-icon" v-if="storeConfigure.configure.navbarIcon" :name="item[1]?.meta?.icon"></SvgIcon>
<span class="list-title">{{ item[1]?.meta?.title || item[0] }}</span>
<SvgIcon class="list-close" name="Close" v-if="item[0] !== '/home'" @click.stop="closeNavbarItem(item[0])">
</SvgIcon>
</div>
</div>
</template>
<script setup>
import { useRoutes } from '@/store/routes.js'
import { useConfigure } from '@/store/configure.js'
const storeRoutes = useRoutes()
const storeConfigure = useConfigure()
const router = useRouter()
/**
* @description: 路由跳转
* @param {String} route: 要跳转的路由
*/
function goRoute(route) {
router.push(route)
}
/**
* @description: 关闭导航的某一项
* @param {String} route: 要关闭的当前项
*/
function closeNavbarItem(route) {
storeRoutes.deleteNavItem(route).then(res => {
goRoute(res[0])
})
}
</script>
<style lang="scss" scoped>
.navBar-list-mode-a {
flex-grow: 1;
display: flex;
align-items: flex-end;
padding: 0 30px;
height: 50px;
overflow: hidden;
&:hover {
overflow: overlay;
overflow-y: hidden;
&::-webkit-scrollbar {
height: 6px;
background-color: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 4px;
}
}
}
.list-icon {
font-size: 16px;
bottom: -0.2em;
color: var(--el-text-color-primary);
}
.list-title {
padding: 0 5px;
font-size: 14px;
color: var(--el-text-color-primary);
}
.list-close {
font-size: 14px;
transform: scale(0, 0);
transition: all 0.3s;
bottom: -0.18em;
color: var(--el-text-color-primary);
}
.list {
position: relative;
cursor: pointer;
flex-shrink: 0;
text-align: center;
overflow: visible;
line-height: 16px;
font-size: 16px;
padding: 0 10px;
display: inline-block;
height: 35px;
line-height: 35px;
transition: all .3s cubic-bezier(.645, .045, .355, 1) !important;
&:hover {
padding: 0 20px;
&::after {
z-index: -1;
content: ' ';
position: absolute;
left: -10px;
right: -10px;
height: 100%;
background-color: var(--el-color-info-light-7);
-webkit-mask: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANoAAAAkBAMAAAAdqzmBAAAAMFBMVEVHcEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlTPQ5AAAAD3RSTlMAr3DvEM8wgCBA379gj5//tJBPAAAAnUlEQVRIx2NgAAM27fj/tAO/xBsYkIHyf9qCT8iWMf6nNQhAsk2f5rYheY7Dnua2/U+A28ZEe8v+F9Ax2v7/F4DbxkUH2wzgtvHTwbYPo7aN2jZq26hto7aN2jZq25Cy7Qvctnw62PYNbls9HWz7S8/G6//PsI6H4396gAUQy1je08W2jxDbpv6nD4gB2uWp+J9eYPsEhv/0BPS1DQBvoBLVZ3BppgAAAABJRU5ErkJggg==);
mask: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANoAAAAkBAMAAAAdqzmBAAAAMFBMVEVHcEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlTPQ5AAAAD3RSTlMAr3DvEM8wgCBA379gj5//tJBPAAAAnUlEQVRIx2NgAAM27fj/tAO/xBsYkIHyf9qCT8iWMf6nNQhAsk2f5rYheY7Dnua2/U+A28ZEe8v+F9Ax2v7/F4DbxkUH2wzgtvHTwbYPo7aN2jZq26hto7aN2jZq25Cy7Qvctnw62PYNbls9HWz7S8/G6//PsI6H4396gAUQy1je08W2jxDbpv6nD4gB2uWp+J9eYPsEhv/0BPS1DQBvoBLVZ3BppgAAAABJRU5ErkJggg==);
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.list-close {
transform: scale(1, 1);
&:hover {
background-color: var(--el-text-color-primary);
color: #fff;
border-radius: 50%;
}
}
}
}
.list-active {
position: relative;
cursor: pointer;
flex-shrink: 0;
overflow: visible;
color: var(--el-color-primary);
padding: 0 20px;
display: inline-block;
height: 35px;
line-height: 35px;
&::before {
z-index: -1;
content: ' ';
position: absolute;
left: -10px;
right: -10px;
height: 100%;
background-color: var(--el-color-primary-light-9);
-webkit-mask: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANoAAAAkBAMAAAAdqzmBAAAAMFBMVEVHcEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlTPQ5AAAAD3RSTlMAr3DvEM8wgCBA379gj5//tJBPAAAAnUlEQVRIx2NgAAM27fj/tAO/xBsYkIHyf9qCT8iWMf6nNQhAsk2f5rYheY7Dnua2/U+A28ZEe8v+F9Ax2v7/F4DbxkUH2wzgtvHTwbYPo7aN2jZq26hto7aN2jZq25Cy7Qvctnw62PYNbls9HWz7S8/G6//PsI6H4396gAUQy1je08W2jxDbpv6nD4gB2uWp+J9eYPsEhv/0BPS1DQBvoBLVZ3BppgAAAABJRU5ErkJggg==);
mask: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANoAAAAkBAMAAAAdqzmBAAAAMFBMVEVHcEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlTPQ5AAAAD3RSTlMAr3DvEM8wgCBA379gj5//tJBPAAAAnUlEQVRIx2NgAAM27fj/tAO/xBsYkIHyf9qCT8iWMf6nNQhAsk2f5rYheY7Dnua2/U+A28ZEe8v+F9Ax2v7/F4DbxkUH2wzgtvHTwbYPo7aN2jZq26hto7aN2jZq25Cy7Qvctnw62PYNbls9HWz7S8/G6//PsI6H4396gAUQy1je08W2jxDbpv6nD4gB2uWp+J9eYPsEhv/0BPS1DQBvoBLVZ3BppgAAAABJRU5ErkJggg==);
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.list-icon,
.list-title,
.list-close {
color: inherit;
transform: scale(1, 1);
}
.list-close {
&:hover {
background-color: var(--el-color-primary);
color: #fff;
border-radius: 50%;
}
}
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<div class="navBar-list-mode-b">
<div class="list" :class="[storeRoutes.activeRoute == item[0] ? 'list-active' : '']" @click="goRoute(item[0])"
v-for="item in storeRoutes.navList">
<SvgIcon class="list-icon" v-if="storeConfigure.configure.navbarIcon" :name="item[1]?.meta?.icon"></SvgIcon>
<span class="list-title">{{ item[1]?.meta?.title || item[0] }}</span>
<SvgIcon class="list-close" name="Close" v-if="item[0] !== '/home'" @click.stop="closeNavbarItem(item[0])">
</SvgIcon>
</div>
</div>
</template>
<script setup>
import { useRoutes } from '@/store/routes.js'
import { useConfigure } from '@/store/configure.js'
const storeRoutes = useRoutes()
const storeConfigure = useConfigure()
const router = useRouter()
/**
* @description: 路由跳转
* @param {String} route: 要跳转的路由
*/
function goRoute(route) {
router.push(route)
}
/**
* @description: 关闭导航的某一项
* @param {String} route: 要关闭的当前项
*/
function closeNavbarItem(route) {
storeRoutes.deleteNavItem(route).then(res => {
goRoute(res[0])
})
}
</script>
<style lang="scss" scoped>
.navBar-list-mode-b {
flex-grow: 1;
display: flex;
align-items: center;
gap: 0 5px;
padding: 0 15px;
height: 60px;
overflow: hidden;
&:hover {
overflow: overlay;
overflow-y: hidden;
&::-webkit-scrollbar {
height: 6px;
background-color: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 4px;
}
}
}
.list-icon {
font-size: 16px;
line-height: 1;
color: var(--el-text-color-primary);
bottom: 0.05em;
}
.list-title {
padding: 0 5px;
font-size: 14px;
line-height: 1;
color: var(--el-text-color-primary);
}
.list-close {
font-size: 0px;
transform: scale(0, 0);
transition: all 0.3s;
color: var(--el-text-color-primary);
}
.list {
cursor: pointer;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 30px;
padding: 0 10px;
border: 1px solid var(--el-color-info-light-7);
background-color: #fff;
border-radius: 4px;
&.list-active {
color: var(--el-color-primary);
border: 1px solid var(--el-color-primary);
background-color: var(--el-color-primary-light-9);
&:hover {
background-color: var(--el-color-primary);
color: #fff;
}
}
&:hover {
background-color: var(--el-color-info-light-7);
.list-icon,
.list-title,
.list-close {
color: inherit;
}
.list-close {
font-size: 14px;
transform: scale(1, 1);
}
}
.list-close {
&:hover {
background-color: var(--el-text-color-primary);
color: #fff;
border-radius: 50%;
}
}
}
</style>

View File

@@ -0,0 +1,176 @@
<template>
<div class="navBar-list-mode-c">
<div :class="[storeRoutes.activeRoute == item[0] ? 'list-active' : 'list']" @click="goRoute(item[0])" v-for="item in storeRoutes.navList">
<SvgIcon class="list-icon" v-if="storeConfigure.configure.navbarIcon" :name="item[1]?.meta?.icon"></SvgIcon>
<span class="list-title">{{ item[1]?.meta?.title || item[0] }}</span>
<SvgIcon class="list-close" name="Close" v-if="item[0] !== '/home'" @click.stop="closeNavbarItem(item[0])"> </SvgIcon>
</div>
</div>
</template>
<script setup>
import { useRoutes } from "@/store/routes.js";
import { useConfigure } from "@/store/configure.js";
const storeRoutes = useRoutes();
const storeConfigure = useConfigure();
const router = useRouter();
/**
* @description: 路由跳转
* @param {String} route: 要跳转的路由
*/
function goRoute(route) {
router.push(route);
}
/**
* @description: 关闭导航的某一项
* @param {String} route: 要关闭的当前项
*/
function closeNavbarItem(route) {
storeRoutes.deleteNavItem(route).then((res) => {
goRoute(res[0]);
});
}
</script>
<style lang="scss" scoped>
.navBar-list-mode-c {
flex-grow: 1;
display: flex;
align-items: center;
gap: 0 5px;
padding: 0 30px;
height: 50px;
overflow: hidden;
&:hover {
overflow: overlay;
overflow-y: hidden;
&::-webkit-scrollbar {
height: 6px;
background-color: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 4px;
}
}
}
.list-icon {
font-size: 16px;
line-height: 1;
color: var(--el-text-color-primary);
bottom: 0.05em;
}
.list-title {
padding: 0 5px;
font-size: 14px;
line-height: 1;
color: var(--el-text-color-primary);
}
.list-close {
font-size: 0px;
transform: scale(0, 0);
transition: all 0.3s;
color: var(--el-text-color-primary);
}
.list {
position: relative;
cursor: pointer;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 35px;
padding: 0 10px;
&::after {
content: " ";
position: absolute;
bottom: 0;
left: 0;
height: 2px;
width: 0;
background-color: var(--el-color-primary);
transition: width 0.3s;
}
&:hover {
background-color: var(--el-color-primary-light-9);
.list-icon,
.list-title,
.list-close {
color: var(--el-color-primary);
}
.list-close {
font-size: 14px;
transform: scale(1, 1);
}
&::after {
width: 100%;
}
}
.list-close {
&:hover {
background-color: var(--el-color-primary);
color: #fff;
border-radius: 50%;
}
}
}
.list-active {
cursor: pointer;
position: relative;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
color: var(--el-color-primary);
height: 35px;
padding: 0 10px;
background-color: var(--el-color-primary-light-9);
&::after {
content: " ";
position: absolute;
bottom: 0;
left: 0;
height: 2px;
width: 100%;
background-color: var(--el-color-primary);
}
.list-icon,
.list-title,
.list-close {
color: inherit;
transform: scale(1, 1);
}
.list-close {
font-size: 14px;
&:hover {
background-color: var(--el-color-primary);
color: #fff;
border-radius: 50%;
}
}
}
</style>

View File

@@ -0,0 +1,139 @@
<template>
<div class="pageHeader">
<div class="routes-case">
<SvgIcon class="sidebar-icon" :name="storeConfigure.configure.collapse ? 'Expand' : 'Fold'" size="20" color="#555"
@click="changeSidebar"></SvgIcon>
<el-breadcrumb separator="/">
<!-- <transition-group name="breadcrumb"> -->
<el-breadcrumb-item v-for="item in storeRoutes.breadcrumb" :key="item.path">
<span style="color: #333;">{{ item?.meta?.title || item.path
}}</span></el-breadcrumb-item>
<!-- </transition-group> -->
</el-breadcrumb>
</div>
<div class="info-case">
<!-- <SvgIcon class="info-icon" name="Operation" @click="operationFunction('operation')"></SvgIcon> -->
<SvgIcon class="info-icon" name="Refresh" @click="operationFunction('refresh')"></SvgIcon>
<el-dropdown style="cursor: pointer" @visible-change="changeDropdownVisible">
<div class="flex align-center" style="gap: 0 10px">
<!-- <img class="info-avatar" :src="storeUser.userInfo.avatar" alt="" srcset="" /> -->
<p class="info-name">{{ storeUser.userInfo.loginName }}</p>
<SvgIcon color="#333" name="arrow-down"></SvgIcon>
</div>
<template #dropdown>
<el-dropdown-menu>
<!-- <el-dropdown-item>个人中心</el-dropdown-item> -->
<el-dropdown-item @click="logOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script setup>
import { useConfigure } from "@/store/configure.js";
import { useUser } from "@/store/user.js";
import { useRoutes } from "@/store/routes.js";
const storeUser = useUser();
const storeRoutes = useRoutes();
// 获取配置
const storeConfigure = useConfigure();
// 侧边栏导航的收起与展开
function changeSidebar() {
storeConfigure.change("collapse", !storeConfigure.configure.collapse);
}
// 下拉菜单
let showDropdown = ref(false);
let rotateUserIcon = ref("0deg");
function changeDropdownVisible() {
showDropdown.value = !showDropdown.value;
rotateUserIcon.value = showDropdown.value ? "180deg" : "0deg";
}
// info 中的按钮操作
const emits = defineEmits(["operation"]);
function operationFunction(type) {
emits("operation", type);
}
// 退出登录
function logOut() {
// 清除缓存 / token 等
_hook.useLocalStorage.clear();
// 使用 reload 时,不需要调用 resetRoute() 重置路由
// 且刷新页面时 pinia 数据会重置
window.location.reload();
}
</script>
<style lang="scss" scoped>
// 面包屑的动画
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all 0.5s ease;
}
.breadcrumb-enter-from,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-leave-active {
position: absolute;
z-index: -1;
transition: all 0s ease;
}
.pageHeader {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
height: 60px;
// border-bottom: 1px solid #efefef;
}
.routes-case {
display: flex;
align-items: center;
justify-content: center;
.sidebar-icon {
margin-right: 10px;
}
}
.info-case {
display: flex;
align-items: center;
gap: 0 16px;
.info-icon {
cursor: pointer;
font-size: 16px;
color: #333;
transition: all 0.3s;
&:hover {
color: var(--el-color-primary);
transform: scale(1.2, 1.2);
}
}
.info-avatar {
border-radius: 2px;
width: 35px;
height: 35px;
}
.info-name {
font-size: 14px;
color: #333;
}
}
</style>

View File

@@ -0,0 +1,124 @@
<template>
<template v-if="props.item.children">
<el-sub-menu
:class="{ 'menu-sub-modeA': configure.menuMode == layoutModeEnum.key[0], 'menu-sub-modeB': configure.menuMode == layoutModeEnum.key[1] }"
v-if="!props.item.meta?.isHide" :index="props.item?.path">
<template #title>
<SvgIcon class="route-icon" :name="props.item?.meta?.icon"></SvgIcon>
<span class="route-title">{{ props.item?.meta?.title || props.item?.path }}</span>
</template>
<sidebar-modeA-sub v-for="route in props.item?.children" :item="route" :key="route.path"></sidebar-modeA-sub>
</el-sub-menu>
<template v-else>
<sidebar-modeA-sub v-for="route in props.item?.children" :item="route" :key="route.path"></sidebar-modeA-sub>
</template>
</template>
<template v-else>
<el-menu-item
:class="{ 'active-menu': activeMenuCount(), 'is-active': activeMenuCount(), 'menu-modeA': configure.menuMode == layoutModeEnum.key[0], 'menu-modeB': configure.menuMode == layoutModeEnum.key[1] }"
v-if="!props.item?.meta?.isHide" :index="props.item?.path">
<SvgIcon class="route-icon" :name="props.item?.meta?.icon"></SvgIcon>
<span class="route-title">{{ props.item?.meta?.title || props.item?.path }}</span>
</el-menu-item>
</template>
</template>
<script setup>
import { useRoutes } from "@/store/routes.js";
import { useConfigure } from "@/store/configure.js";
import { useRoute } from 'vue-router'
const storeRoutes = useRoutes();
const route = useRoute();
// 获取配置
const storeConfigure = useConfigure();
const { configure } = storeToRefs(storeConfigure);
const props = defineProps({
item: {
type: Object,
required: true,
},
});
// 获取枚举值
const { layoutModeEnum } = ENUMS;
function activeMenuCount() {
if (route.meta.activeMenu) {
return props.item?.path == route.meta.activeMenu
} else {
return storeRoutes.activeRoute == props.item?.path
}
}
</script>
<style lang="scss">
.menu-sub-modeA {
.el-sub-menu__title {
&:hover {
background-color: rgba(0, 0, 0, 0);
}
}
}
.menu-sub-modeB {
.el-sub-menu__title {
margin: 0 5px;
color: var(--el-text-color-primary);
&:hover {
background-color: rgba(0, 0, 0, 0);
}
}
.el-icon {
color: var(--el-text-color-primary);
}
}
</style>
<style lang="scss" scoped>
.menu-modeA {
&:hover {
// color: var(--el-menu-active-color);
// background-color: var(--el-color-primary-light-3);
background-color: #efefef;
}
}
.menu-modeA.active-menu {
background-color: var(--el-color-primary);
}
.menu-modeB {
margin: 5px;
border-radius: 5px;
.route-title,
.route-icon {
color: var(--el-text-color-primary);
}
&:hover {
background-color: var(--el-color-primary-light-9);
.route-title,
.route-icon {
color: var(--el-color-primary-light-3);
}
}
}
.menu-modeB.active-menu {
background-color: var(--el-color-primary-light-9);
.route-title,
.route-icon {
color: var(--el-color-primary-light-3);
}
}
</style>

View File

@@ -0,0 +1,77 @@
<template>
<div class="sidebar-mode-a">
<div class="logo-case" v-if="configure.showMenuLogo">
<img class="logo" src="/logo.png" alt="logo" srcset="" />
<transition name="el-fade-in">
<span v-show="!storeConfigure.configure.collapse" style="margin-left: 10px;">{{ storeConfigure.projectName
}}</span>
</transition>
</div>
<el-menu @select="goRoute" :collapse="configure.collapse" :default-active="defaultActive" style="border-right: none"
class="el-menu-vertical-demo">
<sidebar-modea-sub v-for="route in props.list" :key="route.path" :item="route" />
</el-menu>
</div>
</template>
<script setup>
import { useConfigure } from "@/store/configure.js";
import sidebarModeaSub from "./sidebar-modeA-sub.vue";
const props = defineProps({
list: {
type: Array,
default: () => {
return [];
},
required: true,
},
width: {
type: String,
required: true,
},
});
let width = ref(props.width);
// 获取配置
const storeConfigure = useConfigure();
const { configure, defaultActive } = storeToRefs(storeConfigure);
/**
* @description: 路由跳转
* @param {String} index: 路由
*/
const router = useRouter();
function goRoute(index) {
router.push(index);
}
</script>
<style lang="scss">
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: v-bind(width);
}
.sidebar-mode-a {
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
}
.logo-case {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 60px;
overflow: hidden;
.logo {
height: 30px;
border-radius: 6px;
}
}
</style>

View File

@@ -0,0 +1,150 @@
<template>
<div class="sidebar-mode-b">
<el-scrollbar class="scrollbar">
<div class="route-list" :class="{ 'active-route-list': storeRoutes.breadcrumbKeys.includes(item.path) }" v-for="item in data.routesList" @click="goRoute(item.path)">
<SvgIcon class="route-icon" size="16" :name="item?.meta?.icon"></SvgIcon>
<span class="route-title">{{ item?.meta?.title || item.path }}</span>
</div>
</el-scrollbar>
<div :class="['sidebar-mode-b-menu', configure.collapse ? 'sidebar-switch' : 'sidebar-open']">
<sidebar-mode-a menu-trigger="hover" :list="data.activeRouteChildren" width="190px"></sidebar-mode-a>
</div>
</div>
</template>
<script setup>
import sidebarModeA from "./sidebar-modeA.vue";
import { useRoutes } from "@/store/routes.js";
import { useConfigure } from "@/store/configure.js";
// 获取配置
const storeConfigure = useConfigure();
const { configure } = storeToRefs(storeConfigure);
const route = useRoute();
// 获取路由 store
const storeRoutes = useRoutes();
const data = reactive({
routesList: [],
activeRouteChildren: [],
});
/**
* @description: 过滤侧栏可显示的一级路由
* @param {Array} routes: 路由列表
* @return {Array} 过滤好的路由
*/
function filterRoute(routes) {
let arr = [];
routes.forEach((i) => {
if (i?.meta?.isHide == false || i?.meta?.isHide == undefined) {
arr.push(i);
} else {
if (i?.children?.length > 0) {
arr = filterRoute(i.children);
}
}
});
return arr;
}
/**
* @description: 路由跳转
* @param {String} index: 路由
*/
const router = useRouter();
function goRoute(index) {
router.push(index);
}
onMounted(() => {
data.routesList = filterRoute(storeRoutes.routesList);
data.activeRouteChildren = storeRoutes.allRoutes[route.matched[1].path].children;
if (data.activeRouteChildren.length == 0) {
storeConfigure.change("collapse", true);
}
});
watch(
() => storeRoutes.breadcrumbKeys,
() => {
data.activeRouteChildren = storeRoutes.allRoutes[route.matched[1].path]?.children;
if (data?.activeRouteChildren?.length == 0) {
storeConfigure.change("collapse", true);
} else {
storeConfigure.change("collapse", false);
}
},
{ immediate: true }
);
</script>
<style lang="scss" scoped>
.sidebar-mode-b {
display: flex;
height: 100%;
}
.scrollbar {
border-right: 1px solid var(--el-border-color-lighter);
}
.route-list {
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
border-radius: 5px;
margin: 5px;
width: 60px;
height: 60px;
&:hover {
background-color: var(--el-color-primary-light-3);
.route-icon,
.route-title {
color: var(--el-menu-active-color);
}
}
.route-icon,
.route-title {
text-align: center;
color: var(--el-menu-text-color);
font-size: 12px;
}
}
.active-route-list {
background-color: var(--el-color-primary-light-3);
.route-icon,
.route-title {
color: var(--el-menu-active-color);
}
}
.sidebar-switch {
width: 0px;
overflow: hidden;
transition: width 0.3s;
}
.sidebar-open {
width: 190px;
overflow: hidden;
transition: width 0.3s;
}
.sidebar-mode-b-menu {
overflow-y: scroll;
background-color: var(--el-color-white);
height: 100%;
&::-webkit-scrollbar {
display: none;
}
}
</style>

202
src/views/layout/layout.vue Normal file
View File

@@ -0,0 +1,202 @@
<template>
<div class="layout-container">
<div class="layout-case">
<div class="sidebar">
<!-- 侧边栏的布局模式 -->
<sidebar-mode-a v-if="getConfigure.menuMode == layoutModeEnum.key[0]" :list="storeRoutes.routesList"
width="260px"></sidebar-mode-a>
<sidebar-mode-b v-else-if="getConfigure.menuMode == layoutModeEnum.key[1]"></sidebar-mode-b>
</div>
<div class="layout-case" style="flex-direction: column">
<header class="header">
<page-header @operation="operation"></page-header>
<navbar></navbar>
</header>
<main class="main">
<!-- <router-view v-slot="{ Component }" v-if="isRefreshRoute">
<transition :name="getConfigure.componentTransitionMode" mode="out-in"
v-if="getConfigure.componentTransition">
<keep-alive :include="storeRoutes.cachedRoute">
<component :is="Component" />
</keep-alive>
</transition>
<keep-alive v-else :include="storeRoutes.cachedRoute">
<component :is="Component" />
</keep-alive>
</router-view> -->
<router-view v-slot="{ Component }">
<!-- <transition :name="getConfigure.componentTransitionMode" mode="out-in"> -->
<!-- <keep-alive :include="storeRoutes.cachedRoute"> -->
<component :is="Component" />
<!-- </keep-alive> -->
<!-- </transition> -->
<!-- <keep-alive v-else :include="storeRoutes.cachedRoute"> -->
<!-- <component v-else :is="Component" /> -->
<!-- </keep-alive> -->
</router-view>
</main>
<div class="version">©银收客 v{{ packageData.version }}</div>
</div>
</div>
<c-configure v-model="bools.showConfigure"></c-configure>
</div>
</template>
<script setup>
import sidebarModeA from "./components/sidebar-modeA.vue";
import sidebarModeB from "./components/sidebar-modeB.vue";
import pageHeader from "./components/pageHeader.vue";
import navbar from "./components/navBar.vue";
import cConfigure from "./components/configure.vue";
import { useConfigure } from "@/store/configure.js";
import { useRoutes } from "@/store/routes.js";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
const storeRoutes = useRoutes();
import packageData from '../../../package.json'
// 获取枚举值
const { layoutModeEnum } = ENUMS;
// 获取配置
const storeConfigure = useConfigure();
const { configure } = storeToRefs(storeConfigure);
const getConfigure = computed(() => {
return configure.value;
});
// 控制操作的布尔值
const bools = reactive({
showConfigure: false,
});
// 页头的操作
function operation(type) {
switch (type) {
case "operation":
bools.showConfigure = true;
break;
case "refresh":
reload();
break;
}
}
// 局部组件刷新
const isRefreshRoute = ref(true);
function reload() {
NProgress.start();
isRefreshRoute.value = false;
nextTick(() => {
isRefreshRoute.value = true;
NProgress.done();
});
}
</script>
<style>
.vab-drawer .el-drawer__header {
margin-bottom: 0;
}
.el-icon .el-sub-menu__icon-arrow {
color: var(--el-text-color-primary);
}
</style>
<style lang="scss" scoped>
.layout-container {
--versionH: 50px;
}
.version {
height: var(--versionH);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #999;
}
// 页面切换的动画 模式 A
.mainA-enter-active,
.mainA-leave-active {
transition: all 0.5s ease;
}
.mainA-enter-from,
.mainA-leave-active {
opacity: 0;
transform: translateY(100px);
}
.mainA-leave-active {
position: absolute;
z-index: -1;
transition: all 0s ease;
}
// 页面切换的动画 模式 B
.mainB-enter-active,
.mainB-leave-active {
transition: all 0.5s ease;
}
.mainB-enter-from,
.mainB-leave-active {
opacity: 0;
transform: translateX(100px);
}
.mainB-leave-active {
position: absolute;
z-index: -1;
transition: all 0s ease;
}
.layout-container {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
display: flex;
}
.layout-case {
display: flex;
flex-direction: row;
flex: 1;
flex-basis: auto;
box-sizing: border-box;
min-width: 0;
}
.sidebar {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--admin-column-bg-color);
}
.header {
position: relative;
box-sizing: border-box;
flex-shrink: 0;
}
.main {
height: calc(100vh - 60px * 2 - var(--versionH));
display: block;
flex: 1;
flex-basis: auto;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
padding: 0 15px 15px;
background: var(--el-color-info-light-9);
@extend .scrollbar-y;
}
</style>

169
src/views/login/login.vue Normal file
View File

@@ -0,0 +1,169 @@
<template>
<div class="login-case">
<div class="form-case">
<span class="Hello">Hello !</span>
<span class="title">欢迎来到银收客</span>
<el-form ref="ruleFormRef" :rules="rules" :model="form">
<el-form-item prop="loginName">
<el-input class="inp" v-model="form.loginName" clearable autocomplete="new-password" size="large"
:prefix-icon="User" placeholder="请输入账号" style="width: 100%;" />
</el-form-item>
<el-form-item prop="password">
<el-input class="inp" v-model="form.password" clearable autocomplete="new-password" size="large" type="password"
:prefix-icon="Lock" placeholder="请输入密码" style="width: 100%;" />
</el-form-item>
<el-form-item>
<el-select v-model="form.userType" placeholder="请选择机构类型" size="large" style="width: 100%;">
<el-option key="MG" label="平台" value="MG"></el-option>
<el-option key="FO" label="大机构" value="FO"></el-option>
<el-option key="SO" label="小机构" value="SO"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item prop="code">
<div class="code-case">
<el-input class="inp" v-model="form.code" clearable autocomplete="new-password" size="large"
:prefix-icon="CircleCheck" width="100px" placeholder="验证码" />
<verificationCode @getCode="getCode" :key="verificationCodeKey"></verificationCode>
</div>
</el-form-item> -->
<el-form-item>
<el-button type="primary" size="large" :loading="loading" @click="login" style="width: 100%;">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup>
import verificationCode from "@/components/verificationCode.vue";
import { User, Lock, CircleCheck } from "@element-plus/icons-vue";
import { useUser } from "@/store/user.js";
const ruleFormRef = ref("");
const store = useUser();
const router = useRouter();
const loading = ref(false)
onMounted(() => {
// ElMessage({
// message: "请使用用户名为 admin、yonghu1、yonghu2 进行登录测试,来获取不同的权限",
// type: "success",
// duration: 5000,
// });
});
let verificationCodeKey = ref(0);
let trueCode = ref("");
/**
* @description: 获取正确的验证码值
* @param {*} code: 正确的验证码
*/
function getCode(code) {
trueCode.value = code;
}
const form = reactive({
loginName: "",
password: "",
userType: 'MG',
code: "",
});
/**
* @description: 自定义验证 - 验证账号
*/
function checkName(rule, value, callback) {
if (value === "") {
callback(new Error("账号不可为空"));
} else {
callback();
}
}
/**
* @description: 自定义验证 - 验证验证码
*/
function checkCode(rule, value, callback) {
if (value === "") {
callback(new Error("验证码不可为空"));
} else if (value !== trueCode.value) {
verificationCodeKey.value++;
callback(new Error("验证码不正确"));
} else {
callback();
}
}
// form 验证
const rules = reactive({
loginName: [{ validator: checkName, required: true, trigger: "blur" }],
password: [{ required: true, message: "密码不可为空", trigger: "blur" }],
code: [{ validator: checkCode, required: true, trigger: "blur" }],
});
// 登录
async function login() {
//通过 ref 的值触发验证
await ruleFormRef.value.validate((valid) => {
if (valid) {
loading.value = true
const params = {
loginName: form.loginName,
password: form.password,
userType: form.userType
};
store.userlogin(params).then((res) => {
router.replace("/home");
}).catch(err => {
loading.value = false
});
}
});
}
// 回车键触发登录操作
_hook.useKeyStroke("Enter", login);
</script>
<style lang="scss" scoped>
.login-case {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: url('../../assets/logo_bg.png') no-repeat right bottom / contain;
}
.form-case {
position: absolute;
display: flex;
flex-direction: column;
// height: 450px;
left: 20%;
top: 50%;
transform: translateY(-50%);
}
.Hello {
font-weight: bold;
font-size: 30px;
color: #000;
margin-bottom: 10px;
}
.title {
font-weight: 600;
font-size: 40px;
color: #000;
margin-bottom: 50px;
}
.code-case {
display: flex;
align-items: center;
justify-content: space-between;
.inp {
margin-right: 10px;
}
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<div class="svgIcon">
<el-card header="SvgIcon ( 仅支持 ElementPlus Icon )">
<SvgIcon name="ElementPlus" size="50" color="#409eff"></SvgIcon>
</el-card>
<el-card header="参数" style="margin-top: 20px">
<el-table :data="tableData">
<el-table-column prop="param" label="参数" />
<el-table-column prop="explain" label="说明" />
<el-table-column prop="type" label="类型" />
</el-table>
</el-card>
</div>
</template>
<script setup>
const tableData = [
{
param: "name",
explain: "svg 图标名字",
type: "String",
},
{
param: "size",
explain: "svg 大小",
type: "String / Number",
},
{
param: "color",
explain: "svg 颜色",
type: "String",
},
];
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,336 @@
<template>
<div class="card">
<div class="pb15" v-permission="['SO']">
<el-row>
<el-space>
<el-button type="primary" icon="Plus" @click="showDialog = true">添加代理</el-button>
</el-space>
</el-row>
</div>
<el-space>
<el-input placeholder="请输入机构代码搜索" v-model="tableOptions.agencyCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="代理id"></el-table-column>
<el-table-column prop="agencyName" label="代理名称">
<template #default="scope">
<el-text>{{ scope.row.agencyName || scope.row.agencyCode }}</el-text>
</template>
</el-table-column>
<el-table-column prop="agencyCode" label="代理代码"></el-table-column>
<el-table-column prop="current_fee" label="推广费率">
<template #default="scope" v-permission="['MG']">
<el-link type="primary" icon="EditPen" @click="eitorFeeHandle(scope.row)">{{ scope.row.current_fee
}}%</el-link>
</template>
</el-table-column>
<el-table-column prop="parentLoginName" label="上级机构代码"></el-table-column>
<el-table-column prop="sumConsumeFee" label="总流水">
<template #default="scope">
<el-text>{{ scope.row.sumConsumeFee.toFixed(2) }}</el-text>
</template>
</el-table-column>
<el-table-column prop="yestedayConsumeFee" label="今日流水"></el-table-column>
<el-table-column prop="sumfansShareMoney" label="总收益">
<template #default="scope">
<el-link type="primary" icon="search" @click="showTotalEarnings(scope.row.id)">
{{ scope.row.sumfansShareMoney }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="yestedayShareMoney" label="今日收益"></el-table-column>
<el-table-column prop="sumAccount" label="商家数量"></el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" type="primary" icon="DataLine"
@click="checkChartHandle(scope.row.id)">详细数据</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog title="修改推广费率" v-model="showFeeDialog" @closed="feeDialogClosed">
<el-form ref="formFeeRef" :model="feeForm" :rules="feeRules" label-width="100">
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="feeForm.fee">
<template #append>%</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showFeeDialog = false">取消</el-button>
<el-button type="primary" :loading="showFeeLoading" @click="feeSubmitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<el-dialog title="添加代理" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item label="代理类型">
<el-select v-model="form.userType" disabled>
<el-option :key="item.type_code" :label="item.type_name" :value="item.type_code"
v-for="item in organizationList" key="item.type_code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="agencyName" label="代理名称">
<el-input placeholder="请输入机构名称" v-model="form.agencyName" />
</el-form-item>
<el-form-item prop="angencyCode" label="代理代码">
<el-input placeholder="请输入机构代码" :maxlength="11" show-word-limit v-model="form.angencyCode" />
</el-form-item>
<el-form-item prop="passowrd" label="密码">
<el-input type="password" show-password placeholder="请输入密码" :maxlength="11" v-model="form.passowrd" />
</el-form-item>
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="form.fee">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item prop="phone" label="联系方式">
<el-input placeholder="请输入手机号" v-model="form.phone" />
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<totalEarnings ref="totalEarningsRef" />
<el-dialog title="详细数据" width="90%" v-model="showChartCard">
<chart-card v-if="showChartCard" :user-id="userId" />
</el-dialog>
</div>
</template>
<script setup>
import { addAgency, queryAgency, modifyFee } from '@/api/organization.js'
import { ElMessage } from 'element-plus'
import { validPhone, organizationList, addOrganizations } from '@/utils'
import { onMounted, reactive } from 'vue';
import { useUser } from '@/store/user.js'
// 图表相关
import chartCard from '@/components/chartCard.vue';
const showChartCard = ref(false)
const userId = ref()
function checkChartHandle(id) {
userId.value = id
showChartCard.value = true
}
// totalEarnings组件相关
import totalEarnings from '@/components/totalEarnings.vue';
const totalEarningsRef = ref('')
function showTotalEarnings(parent_user_id) {
totalEarningsRef.value.show(parent_user_id)
}
const storeUser = useUser()
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const showFeeDialog = ref(false)
const showFeeLoading = ref(false)
// 获取添加小机构表单实例
let formRef = ref(null)
// 获取修改费率表单实例
let formFeeRef = ref(null)
// 创建表单
const form = reactive({
agencyName: '',
angencyCode: '',
passowrd: '',
fee: '',
userType: addOrganizations[storeUser.userInfo.userType],
phone: '',
})
// 创建修改费率表单
const feeForm = reactive({
id: '',
fee: ''
})
const feeRules = reactive({
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 自定义校验密码
function passowrdValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (value.length < 6) {
return callback(new Error('密码最少6位'))
} else {
callback()
}
}
// 自定义校验手机号
function phoneValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (!validPhone(value)) {
return callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
// 创建form校验规则
const rules = reactive({
agencyName: [
{
required: true,
message: '',
trigger: 'blur'
}
],
angencyCode: [
{
required: true,
message: '',
trigger: 'blur'
}
],
passowrd: [
{
required: true,
validator: passowrdValidate,
trigger: 'blur'
}
],
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
],
phone: [
{
required: true,
validator: phoneValidate,
trigger: 'blur'
}
]
})
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
}
// 修改费率关闭
function feeDialogClosed() {
formFeeRef.value.resetFields()
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild, fields) => {
if (vaild) {
try {
formLoading.value = true
await addAgency(form)
formLoading.value = false
showDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
// 提交修改费率
async function feeSubmitHandle() {
await formFeeRef.value.validate(async (vaild) => {
if (vaild) {
try {
showFeeLoading.value = true
await modifyFee(feeForm)
showFeeLoading.value = false
showFeeDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
showFeeLoading.value = false
}
}
})
}
// 修改费率
function eitorFeeHandle(row) {
feeForm.id = row.id
feeForm.fee = row.current_fee
showFeeDialog.value = true
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryAgencyHandle()
}
// 获取机构列表
async function queryAgencyHandle() {
try {
const res = await queryAgency({
agencyCode: tableOptions.agencyCode,
pageNum: tableOptions.pageNum,
pageSzie: tableOptions.pageSzie,
userType: 'AG',
isExtend: ''
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
} catch (error) { }
}
onMounted(() => {
queryAgencyHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 355px);
}
</style>

View File

@@ -0,0 +1,336 @@
<template>
<div class="card">
<div class="pb15">
<el-row v-permission="['MG']">
<el-space>
<el-button type="primary" icon="Plus" @click="showDialog = true">添加大机构</el-button>
</el-space>
</el-row>
</div>
<el-space>
<el-input placeholder="请输入机构代码搜索" v-model="tableOptions.agencyCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border v-loading="tableOptions.loading">
<el-table-column prop="id" label="机构id"></el-table-column>
<el-table-column prop="agencyName" label="机构名称">
<template #default="scope">
<el-text>{{ scope.row.agencyName || scope.row.agencyCode }}</el-text>
</template>
</el-table-column>
<el-table-column prop="agencyCode" label="机构代码"></el-table-column>
<el-table-column prop="current_fee" label="推广费率">
<template #default="scope">
<el-link type="primary" icon="EditPen" @click="eitorFeeHandle(scope.row)">
{{ scope.row.current_fee }}%
</el-link>
</template>
</el-table-column>
<el-table-column prop="parentLoginName" label="上级机构代码"></el-table-column>
<el-table-column prop="sumConsumeFee" label="总流水">
<template #default="scope">
<el-text>{{ scope.row.sumConsumeFee.toFixed(2) }}</el-text>
</template>
</el-table-column>
<el-table-column prop="yestedayConsumeFee" label="今日流水"></el-table-column>
<el-table-column prop="sumfansShareMoney" label="总收益">
<template #default="scope">
<el-link type="primary" icon="search" @click="showTotalEarnings(scope.row.id)">
{{ scope.row.sumfansShareMoney }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="yestedayShareMoney" label="今日收益"></el-table-column>
<el-table-column prop="sumAccount" label="商家数量"></el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" type="primary" icon="DataLine"
@click="checkChartHandle(scope.row.id)">详细数据</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog title="修改推广费率" v-model="showFeeDialog" @closed="feeDialogClosed">
<el-form ref="formFeeRef" :model="feeForm" :rules="feeRules" label-width="100">
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="feeForm.fee">
<template #append>%</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showFeeDialog = false">取消</el-button>
<el-button type="primary" :loading="showFeeLoading" @click="feeSubmitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<el-dialog title="添加大机构" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item label="机构类型">
<el-select v-model="form.userType" disabled>
<el-option :key="item.type_code" :label="item.type_name" :value="item.type_code"
v-for="item in organizationList" key="item.type_code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="agencyName" label="机构名称">
<el-input placeholder="请输入机构名称" v-model="form.agencyName" />
</el-form-item>
<el-form-item prop="angencyCode" label="机构代码">
<el-input placeholder="请输入机构代码" :maxlength="11" show-word-limit v-model="form.angencyCode" />
</el-form-item>
<el-form-item prop="passowrd" label="密码">
<el-input type="password" show-password placeholder="请输入密码" :maxlength="11" v-model="form.passowrd" />
</el-form-item>
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="form.fee">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item prop="phone" label="联系方式">
<el-input placeholder="请输入手机号" v-model="form.phone" />
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<totalEarnings ref="totalEarningsRef" />
<el-dialog title="详细数据" width="90%" v-model="showChartCard">
<chart-card v-if="showChartCard" :user-id="userId" />
</el-dialog>
</div>
</template>
<script setup>
import { addAgency, queryAgency, modifyFee } from '@/api/organization.js'
import { ElMessage } from 'element-plus'
import { validPhone, organizationList, addOrganizations } from '@/utils'
import { onMounted, reactive, ref } from 'vue';
import { useUser } from '@/store/user.js'
import chartCard from '@/components/chartCard.vue';
const showChartCard = ref(false)
const userId = ref()
function checkChartHandle(id) {
userId.value = id
showChartCard.value = true
}
const storeUser = useUser()
// totalEarnings组件相关
import totalEarnings from '@/components/totalEarnings.vue';
const totalEarningsRef = ref('')
function showTotalEarnings(parent_user_id) {
totalEarningsRef.value.show(parent_user_id)
}
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const showFeeDialog = ref(false)
const showFeeLoading = ref(false)
// 获取添加小机构表单实例
let formRef = ref(null)
// 获取修改费率表单实例
let formFeeRef = ref(null)
// 创建表单
const form = reactive({
agencyName: '',
angencyCode: '',
passowrd: '',
fee: '',
userType: addOrganizations[storeUser.userInfo.userType],
phone: ''
})
// 创建修改费率表单
const feeForm = reactive({
id: '',
fee: ''
})
const feeRules = reactive({
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 自定义校验密码
function passowrdValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (value.length < 6) {
return callback(new Error('密码最少6位'))
} else {
callback()
}
}
// 自定义校验手机号
function phoneValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (!validPhone(value)) {
return callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
// 创建form校验规则
const rules = reactive({
agencyName: [
{
required: true,
message: '',
trigger: 'blur'
}
],
angencyCode: [
{
required: true,
message: '',
trigger: 'blur'
}
],
passowrd: [
{
required: true,
validator: passowrdValidate,
trigger: 'blur'
}
],
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
],
phone: [
{
required: true,
validator: phoneValidate,
trigger: 'blur'
}
]
})
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
}
// 修改费率关闭
function feeDialogClosed() {
formFeeRef.value.resetFields()
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild, fields) => {
if (vaild) {
try {
formLoading.value = true
await addAgency(form)
formLoading.value = false
showDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
// 提交修改费率
async function feeSubmitHandle() {
await formFeeRef.value.validate(async (vaild) => {
if (vaild) {
try {
showFeeLoading.value = true
await modifyFee(feeForm)
showFeeLoading.value = false
showFeeDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
showFeeLoading.value = false
}
}
})
}
// 修改费率
function eitorFeeHandle(row) {
feeForm.id = row.id
feeForm.fee = row.current_fee
showFeeDialog.value = true
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryAgencyHandle()
}
// 获取机构列表
async function queryAgencyHandle() {
try {
const res = await queryAgency({
agencyCode: tableOptions.agencyCode,
pageNum: tableOptions.pageNum,
pageSzie: tableOptions.pageSzie,
userType: 'FO',
isExtend: ''
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
} catch (error) { }
}
onMounted(() => {
queryAgencyHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 358px);
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<el-upload ref="uploadRef" v-model:file-list="fileList" list-type="picture-card" :limit="1" :on-exceed="handleExceed"
:auto-upload="false" @change="selectFile" @remove="removeFile" @preview="previewHandle">
<el-icon>
<Plus />
</el-icon>
</el-upload>
<el-dialog v-model="show" title="图片预览" width="30%">
<img class="img" w-full :src="imgUrl" alt="Preview Image" />
</el-dialog>
</template>
<script setup>
import { defineExpose } from 'vue'
import { genFileId } from 'element-plus'
const show = ref(false)
const imgUrl = ref('')
const uploadRef = ref(null)
const fileList = ref([])
const emit = defineEmits(['selectFile', 'removeFile'])
// 只能选择一个文件,替换之前的文件
const handleExceed = (files) => {
uploadRef.value.clearFiles()
const file = files[0]
file.uid = genFileId()
uploadRef.value.handleStart(file)
}
// 选择图片
const selectFile = async (file) => {
emit('selectFile', file)
fileList.value = [file]
}
// 移除图片
const removeFile = async (file) => {
fileList.value = []
emit('removeFile')
}
// 预览图片
function previewHandle({ url }) {
show.value = true
imgUrl.value = url
}
// 父级传值
const pselectFile = async (file) => {
fileList.value = [file]
}
defineExpose({
pselectFile
})
</script>
<style scoped lang="scss">
.img {
width: 100%;
}
</style>

View File

@@ -0,0 +1,80 @@
<!-- 通道进件信息 -->
<template>
<el-form ref="formRef" :model="form" label-width="120" label-position="left">
<div class="title_wrap">
<el-text>通道进件组1</el-text>
</div>
<el-form-item label="审核备注组" class="mt15">
<el-select v-model="form.remarkGroup">
<el-option :value="0" label="退回" />
<el-option :value="1" label="通过" />
</el-select>
</el-form-item>
<el-form-item label="审核备注">
<el-input type="textarea" :autosize="{ minRows: 4 }" v-model="form.remark" placeholder="请输入审核备注"
style="width: 50%" />
</el-form-item>
<el-form-item label="通道选择">
<el-radio-group disabled v-model="form.aisle">
<el-radio :label="1">随行付</el-radio>
<el-radio :label="2">银盛</el-radio>
<el-radio :label="3">拉卡拉</el-radio>
<el-radio :label="4">银盛D1</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="默认结算方式">
<el-input v-model="form.settle" placeholder="请输入默认结算方式" style="width: 50%" />
</el-form-item>
<el-form-item label="审核状态">
<el-input v-model="form.authStatus" disabled style="width: 50%" />
</el-form-item>
<div class="title_wrap">
<el-text>通道进件组2</el-text>
</div>
<el-form-item label="审核备注组" class="mt15">
<el-select v-model="form.remarkGroup">
<el-option :value="0" label="退回" />
<el-option :value="1" label="通过" />
</el-select>
</el-form-item>
<el-form-item label="审核备注">
<el-input type="textarea" :autosize="{ minRows: 4 }" v-model="form.remark" placeholder="请输入审核备注"
style="width: 50%" />
</el-form-item>
<el-form-item label="通道选择">
<el-radio-group disabled v-model="form.aisle">
<el-radio :label="1">随行付</el-radio>
<el-radio :label="2">银盛</el-radio>
<el-radio :label="3">拉卡拉</el-radio>
<el-radio :label="4">银盛D1</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="默认结算方式">
<el-input v-model="form.settle" placeholder="请输入默认结算方式" style="width: 50%" />
</el-form-item>
<el-form-item label="审核状态">
<el-input v-model="form.authStatus" disabled style="width: 50%" />
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary">通过</el-button>
<el-button type="danger">驳回</el-button>
<el-button type="danger">驳回并禁止进件</el-button>
</el-space>
</el-form-item>
</el-form>
</template>
<script setup>
const form = reactive({
remarkGroup: 0,
remark: '',
aisle: '',
settle: '',
authStatus: ''
})
</script>
<style scoped lang="scss">
@import './common.scss';
</style>

View File

@@ -0,0 +1,359 @@
<!-- 实名认证信息 -->
<template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120" label-position="left">
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="username" label="推广员名称">
<el-input v-model="form.username" placeholder="请输入推广员名称" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="loginname" label="登录账号">
<el-input v-model="form.loginname" placeholder="请输入登录账号" />
</el-form-item>
</el-col>
</el-row>
<div class="title_wrap">
<el-text>实名身份证</el-text>
</div>
<el-row :gutter="gutter" class="mt15">
<el-col :span="span">
<el-form-item prop="idCard.certname" label="姓名">
<el-input v-model="form.idCard.certname" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="idCard.certno" label="身份证号码">
<el-input v-model="form.idCard.certno" placeholder="请输入身份证号码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="idCard.certstarttime" label="发放日期">
<el-date-picker style="width: 100%;" v-model="form.idCard.certstarttime" type="date"
placeholder="请选择发放日期" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="idCard.certendtime" label="失效日期">
<el-date-picker style="width: 100%;" v-model="form.idCard.certendtime" type="date"
placeholder="请选择发放日期" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="idCard.imgpositive" label="身份证正面">
<uploadCard ref="idCardRef1" @selectFile="file => form.idCard.imgpositive = file"
@removeFile="form.idCard.imgpositive = ''" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="idCard.imgnegative" label="身份证反面">
<uploadCard ref="idCardRef2" @selectFile="file => form.idCard.imgnegative = file"
@removeFile="form.idCard.imgnegative = ''" />
</el-form-item>
</el-col>
</el-row>
<div class="title_wrap">
<el-text>实名银行卡</el-text>
</div>
<el-row :gutter="gutter" class="mt15">
<el-col :span="span">
<el-form-item prop="bankCard.bankcardno" label="银行卡号">
<el-input v-model="form.bankCard.bankcardno" placeholder="请输入银行卡号" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="bankCard.phone" label="预留手机号">
<el-input v-model="form.bankCard.phone" placeholder="请输入预留手机号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="bankCard.bank" label="开户行地区">
<address-card ref="addressRef" placeholder="请选择开户行地区" style="width: 100%;"
@change="selectBankAddress" />
</el-form-item>
</el-col>
<el-col :span="span"></el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="bankCard.bankname" label="开户银行">
<el-select style="width: 100%;" v-model="form.bankCard.bankname" placeholder="请选择开户银行"
@change="banknameChange">
<el-option v-for="item in bankList" :key="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="bankCard.contactline" label="开户支行">
<el-select style="width: 100%;" v-model="form.bankCard.contactline" placeholder="请选择开户支行">
<el-option :label="item.cnapsName" :value="item.cnapsCode" v-for="item in bankBranchs"
:key="item.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="bankCard.imgurl" label="银行卡照片">
<upload-card ref="uploadBank" @selectFile="file => form.bankCard.imgurl = file"
@removeFile="form.bankCard.imgurl = ''" />
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" @click="submitHandle">立即提交</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import bankList from './bankList'
import { ElMessage } from 'element-plus'
import { uploadOSS } from '@/api/home.js'
import uploadCard from './uploadCard.vue'
import addressCard from '@/components/addressCard.vue'
import { merchantInfoDetail, getBranchList, updatePromoterInformation } from '@/api/shop.js'
import { useRoute } from 'vue-router'
const route = useRoute()
const formRef = ref(null)
const idCardRef1 = ref(null)
const idCardRef2 = ref(null)
const uploadBank = ref(null)
const addressRef = ref(null)
const bankBranchs = ref([])
const span = ref(10)
const gutter = ref(50)
const form = reactive({
status: '',
id: '',
merchantcode: route.query.merchantcode,
userid: route.query.id,
username: route.query.name,
loginname: route.query.account,
idCard: {
id: '',
userid: '',
certname: '',
certno: '',
certstarttime: '',
certendtime: '',
imgpositive: '',
imgnegative: ''
},
bankCard: {
id: '',
userid: '',
bankcardno: '',
phone: '',
branchprovince: '',
branchcity: '',
brancharea: '',
bankname: '',
contactline: '',
imgurl: '',
branchProvinceCode: '',
branchCityCode: '',
branchAreaCode: ''
}
})
const rules = reactive({
username: [
{
required: true,
message: '',
trigger: 'blur'
}
],
loginname: [
{
required: true,
message: '',
trigger: 'blur'
}
],
idCard: {
certname: [
{
required: true,
message: '',
trigger: 'blur'
}
],
certno: [
{
required: true,
message: '',
trigger: 'blur'
}
],
certstarttime: [
{
required: true,
message: '',
trigger: 'blur'
}
],
certendtime: [
{
required: true,
message: '',
trigger: 'blur'
}
],
imgpositive: [
{
required: true,
message: '请选择身份证正面照片',
trigger: 'change'
}
],
imgnegative: [
{
required: true,
message: '请选择身份证反面照片',
trigger: 'change'
}
]
},
bankCard: {
bankcardno: [
{
required: true,
message: '',
trigger: 'blur'
}
],
phone: [
{
required: true,
message: '',
trigger: 'blur'
}
],
bankname: [
{
required: true,
message: '',
trigger: 'blur'
}
],
bank: [
{
required: true,
validator: (rule, value, callback) => {
if (!form.bankCard.branchprovince || !form.bankCard.branchcity || !form.bankCard.brancharea) {
return callback(new Error('请完善开户行地区信息'))
} else {
callback()
}
},
trigger: 'change'
}
],
contactline: [
{
required: true,
message: '',
trigger: 'change'
}
],
imgurl: [
{
required: true,
message: '请选择银行卡照片',
trigger: 'blur'
}
]
}
})
// 获取省市区
function selectBankAddress(e) {
if (e[1].label != form.bankCard.branchcity) {
form.bankCard.bankname = ''
form.bankCard.contactline = ''
}
form.bankCard.branchprovince = e[0].label
form.bankCard.branchcity = e[1].label
form.bankCard.brancharea = e[2].label
form.bankCard.branchProvinceCode = e[0].code
form.bankCard.branchCityCode = e[1].code
form.bankCard.branchAreaCode = e[2].code
}
// 确认选择开户银行
async function banknameChange(val, city) {
try {
if (form.bankCard.branchcity || city) {
const res = await getBranchList({
bankName: val,
cityName: city || form.bankCard.branchcity
})
form.bankCard.contactline = ''
bankBranchs.value = res.branchList
}
} catch (error) { }
}
// 提交表单
async function submitHandle() {
await formRef.value.validate(async vaild => {
if (vaild) {
try {
if (form.idCard.imgpositive.uid) {
form.idCard.imgpositive = await uploadOSS(form.idCard.imgpositive.raw)
}
if (form.idCard.imgnegative.uid) {
form.idCard.imgnegative = await uploadOSS(form.idCard.imgnegative.raw)
}
if (form.bankCard.imgurl.uid) {
form.bankCard.imgurl = await uploadOSS(form.bankCard.imgurl.raw)
}
await updatePromoterInformation(form)
ElMessage.success('提交成功')
} catch (error) {
console.log('334:提交表单===', error)
}
}
})
}
// 获取实名认证信息
async function merchantInfoDetailAjax() {
try {
const res = await merchantInfoDetail(route.query.id)
await banknameChange(res.bankCard.bankname, res.bankCard.branchcity)
form.id = res.id
form.status = res.status
form.bankCard = res.bankCard
form.idCard = res.idCard
idCardRef1.value.pselectFile({ url: res.idCard.imgpositive })
idCardRef2.value.pselectFile({ url: res.idCard.imgnegative })
uploadBank.value.pselectFile({ url: res.bankCard.imgurl })
addressRef.value.setValue([res.bankCard.branchProvinceCode, res.bankCard.branchCityCode, res.bankCard.branchAreaCode])
} catch (error) {
console.log('获取实名认证信息:', error)
}
}
onMounted(() => {
merchantInfoDetailAjax()
})
</script>
<style scoped lang="scss">
@import './common.scss';
</style>

View File

@@ -0,0 +1,19 @@
export default [
'工商银行',
'交通银行',
'招商银行',
'民生银行',
'中信银行',
'浦发银行',
'兴业银行',
'光大银行',
'广发银行',
'平安银行',
'北京银行',
'华夏银行',
'农业银行',
'建设银行',
'邮政储蓄银行',
'中国银行',
'宁波银行'
]

View File

@@ -0,0 +1,20 @@
.title_wrap {
padding: 14px 20px;
background-color: #f9f9f9;
position: relative;
display: flex;
flex-direction: column;
:deep(.el-text) {
align-self: flex-start;
}
&::before {
content: "";
width: 4px;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: var(--el-color-primary);
}
}

View File

@@ -0,0 +1,374 @@
<!-- 结算信息 -->
<template>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form ref="d1FormRef" :model="d1Form" label-width="120" label-position="left">
<div class="title_wrap">
<el-text>D1</el-text>
<el-text type="danger" size="small" style="margin-top: 6px;">小微
(请保持银行卡信息(证件号码开户名卡号预留手机号)的匹配性)</el-text>
</div>
<el-form-item label="开户行地区" class="mt15">
<address-card ref="d1AddressRef" placeholder="请选择开户行地区" @change="d1SelectBankAddress"
style="width: 80%;" />
</el-form-item>
<el-form-item label="开户银行">
<el-select style="width: 80%;" v-model="d1Form.bankCard.bankname" placeholder="请选择开户银行"
@change="d1BanknameChange">
<el-option v-for="item in bankList" :key="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="开户支行">
<el-select style="width: 80%;" v-model="d1Form.bankCard.contactline" placeholder="请选择开户支行">
<el-option :label="item.cnapsName" :value="item.cnapsCode" v-for="item in bankBranchs"
:key="item.id" />
</el-select>
</el-form-item>
<el-form-item label="支行联行号">
<el-input v-model="d1Form.bankCard.contactline" disabled placeholder="请输入支行联行号" style="width: 80%;" />
</el-form-item>
<el-form-item label="开户名">
<el-input v-model="d1Form.bankCard.bankholder" placeholder="请输入开户名" style="width: 80%;" />
</el-form-item>
<el-form-item label="开户账号">
<el-input v-model="d1Form.bankCard.bankcardno" placeholder="请输入开户账号" style="width: 80%;" />
</el-form-item>
<el-form-item label="预留手机号">
<el-input v-model="d1Form.bankCard.phone" placeholder="请输入预留手机号" style="width: 80%;" />
</el-form-item>
<el-form-item label="身份证号码">
<el-input v-model="d1Form.idcard.certno" placeholder="请输入身份证号码" style="width: 80%;" />
</el-form-item>
<el-form-item label="发放日期">
<el-date-picker style="width: 80%;" v-model="d1Form.idcard.createtime" type="date"
placeholder="请选择发放日期" />
</el-form-item>
<el-form-item label="失效日期">
<el-date-picker style="width: 80%;" v-model="d1Form.idcard.certendtime" type="date"
placeholder="请选择失效日期" />
</el-form-item>
<el-form-item label="身份证正面">
<uploadCard ref="d1idcardRef1" @selectFile="file => d1Form.idcard.imgpositive = file"
@removeFile="d1Form.idcard.imgpositive = ''" />
</el-form-item>
<el-form-item label="身份证反面">
<uploadCard ref="d1idcardRef2" @selectFile="file => d1Form.idcard.imgnegative = file"
@removeFile="d1Form.idcard.imgnegative = ''" />
</el-form-item>
<el-form-item label="结算卡图片">
<uploadCard ref="d1BankRef3" @selectFile="file => d1Form.bankCard.imgurl = file"
@removeFile="d1Form.bankCard.imgurl = ''" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="d1SubmitHandle">保存-D1</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="span">
<el-form ref="d0FormRef" :model="d0Form" label-width="120" label-position="left">
<div class="title_wrap">
<el-text>D0</el-text>
<el-text type="danger" size="small" style="margin-top: 6px;">小微
(请保持银行卡信息(证件号码开户名卡号预留手机号)的匹配性)</el-text>
</div>
<el-form-item label="开户行地区" class="mt15">
<address-card ref="d0AddressRef" placeholder="请选择开户行地区" @change="d0SelectBankAddress"
style="width: 80%;" />
</el-form-item>
<el-form-item label="开户银行">
<el-select style="width: 80%;" v-model="d0Form.bankCard.bankname" placeholder="请选择开户银行"
@change="d0BanknameChange">
<el-option v-for="item in bankList" :key="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="开户支行">
<el-select style="width: 80%;" v-model="d0Form.bankCard.contactline" placeholder="请选择开户支行">
<el-option :label="item.cnapsName" :value="item.cnapsCode" v-for="item in bankBranchs"
:key="item.id" />
</el-select>
</el-form-item>
<el-form-item label="支行联行号">
<el-input v-model="d0Form.bankCard.contactline" disabled placeholder="请输入支行联行号" style="width: 80%;" />
</el-form-item>
<el-form-item label="开户名">
<el-input v-model="d0Form.bankCard.bankholder" placeholder="请输入开户名" style="width: 80%;" />
</el-form-item>
<el-form-item label="开户账号">
<el-input v-model="d0Form.bankCard.bankcardno" placeholder="请输入开户账号" style="width: 80%;" />
</el-form-item>
<el-form-item label="预留手机号">
<el-input v-model="d0Form.bankCard.phone" placeholder="请输入预留手机号" style="width: 80%;" />
</el-form-item>
<el-form-item label="身份证号码">
<el-input v-model="d0Form.idcard.certno" placeholder="请输入身份证号码" style="width: 80%;" />
</el-form-item>
<el-form-item label="发放日期">
<el-date-picker style="width: 80%;" v-model="d0Form.idcard.createtime" type="date"
placeholder="请选择发放日期" />
</el-form-item>
<el-form-item label="失效日期">
<el-date-picker style="width: 80%;" v-model="d0Form.idcard.certendtime" type="date"
placeholder="请选择失效日期" />
</el-form-item>
<el-form-item label="身份证正面">
<uploadCard ref="d0idcardRef1" @selectFile="file => d0Form.idcard.imgpositive = file"
@removeFile="d0Form.idcard.imgpositive = ''" />
</el-form-item>
<el-form-item label="身份证反面">
<uploadCard ref="d0idcardRef2" @selectFile="file => d0Form.idcard.imgnegative = file"
@removeFile="d0Form.idcard.imgnegative = ''" />
</el-form-item>
<el-form-item label="结算卡图片">
<uploadCard ref="d0BankRef3" @selectFile="file => d0Form.bankCard.imgurl = file"
@removeFile="d0Form.bankCard.imgurl = ''" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="d0SubmitHandle">保存-D0</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<script setup>
import bankList from './bankList';
import addressCard from '@/components/addressCard.vue'
import uploadCard from './uploadCard.vue'
import { uploadOSS } from '@/api/home.js'
import { merchBaseAccount, getBranchList, updateAccount } from '@/api/shop.js'
import { useRoute } from 'vue-router'
const route = useRoute()
const span = ref(12)
const gutter = ref(50)
const d1FormRef = ref(null)
const d1AddressRef = ref(null)
const d1idcardRef1 = ref(null)
const d1idcardRef2 = ref(null)
const d1BankRef3 = ref(null)
const bankBranchs = ref([])
const d1Form = reactive({
userid: route.query.id,
channeltype: 'D1',
bankCard: {
id: '',
userid: '',
bankholder: '',
bankcardno: '',
bankname: '',
branchname: '',
accounttype: '',
contactline: '',
branchprovince: '',
branchProvinceCode: '',
branchcity: '',
branchCityCode: '',
brancharea: '',
branchAreaCode: '',
bankaddressno: '',
phone: '',
imgurl: ''
},
idcard: {
id: '',
userid: '',
usertype: '',
certtype: '',
certno: '',
certname: '',
certstarttime: '',
certendtime: '',
certaddress: '',
createtime: '',
updatetime: '',
imgpositive: '',
imgnegative: '',
virtypeflag: ''
}
})
// d1获取省市区
function d1SelectBankAddress(e) {
if (e[1].label != d1Form.bankCard.branchcity) {
d1Form.bankCard.bankname = ''
d1Form.bankCard.contactline = ''
}
d1Form.bankCard.branchprovince = e[0].label
d1Form.bankCard.branchcity = e[1].label
d1Form.bankCard.brancharea = e[2].label
d1Form.bankCard.branchProvinceCode = e[0].code
d1Form.bankCard.branchCityCode = e[1].code
d1Form.bankCard.branchAreaCode = e[2].code
}
// d1确认选择开户银行
async function d1BanknameChange(val, city) {
try {
if (d1Form.bankCard.branchcity || city) {
const res = await getBranchList({
bankName: val,
cityName: city || d1Form.bankCard.branchcity
})
d1Form.bankCard.contactline = ''
bankBranchs.value = res.branchList
}
} catch (error) {
console.log('确认选择开户银行error', error)
}
}
// D1提交表单
async function d1SubmitHandle() {
try {
if (d1Form.idcard.imgpositive.uid) {
d1Form.idcard.imgpositive = await uploadOSS(d1Form.idcard.imgpositive.raw)
}
if (d1Form.idcard.imgnegative.uid) {
d1Form.idcard.imgnegative = await uploadOSS(d1Form.idcard.imgnegative.raw)
}
if (d1Form.bankCard.imgurl.uid) {
d1Form.bankCard.imgurl = await uploadOSS(d1Form.bankCard.imgurl.raw)
}
await updateAccount(d1Form)
ElMessage.success('提交成功')
} catch (error) {
console.log('D1提交表单error', error)
}
}
const d0AddressRef = ref(null)
const d0idcardRef1 = ref(null)
const d0idcardRef2 = ref(null)
const d0BankRef3 = ref(null)
const d0FormRef = ref(null)
const d0Form = reactive({
userid: route.query.id,
channeltype: 'D0',
bankCard: {
id: '',
userid: '',
bankholder: '',
bankcardno: '',
bankname: '',
branchname: '',
accounttype: '',
contactline: '',
branchprovince: '',
branchProvinceCode: '',
branchcity: '',
branchCityCode: '',
brancharea: '',
branchAreaCode: '',
bankaddressno: '',
phone: '',
imgurl: ''
},
idcard: {
id: '',
userid: '',
usertype: '',
certtype: '',
certno: '',
certname: '',
certstarttime: '',
certendtime: '',
certaddress: '',
createtime: '',
updatetime: '',
imgpositive: '',
imgnegative: '',
virtypeflag: ''
}
})
const d0Rule = reactive({})
// d0获取省市区
function d0SelectBankAddress(e) {
if (e[1].label != d0Form.bankCard.branchcity) {
d0Form.bankCard.bankname = ''
d0Form.bankCard.contactline = ''
}
d0Form.bankCard.branchprovince = e[0].label
d0Form.bankCard.branchcity = e[1].label
d0Form.bankCard.brancharea = e[2].label
d0Form.bankCard.branchProvinceCode = e[0].code
d0Form.bankCard.branchCityCode = e[1].code
d0Form.bankCard.branchAreaCode = e[2].code
}
// d0确认选择开户银行
async function d0BanknameChange(val, city) {
try {
if (d0Form.bankCard.branchcity || city) {
const res = await getBranchList({
bankName: val,
cityName: city || d0Form.bankCard.branchcity
})
d0Form.bankCard.contactline = ''
bankBranchs.value = res.branchList
}
} catch (error) {
console.log('确认选择开户银行error', error)
}
}
// D0提交表单
async function d0SubmitHandle() {
try {
if (d0Form.idcard.imgpositive.uid) {
d0Form.idcard.imgpositive = await uploadOSS(d0Form.idcard.imgpositive.raw)
}
if (d0Form.idcard.imgnegative.uid) {
d0Form.idcard.imgnegative = await uploadOSS(d0Form.idcard.imgnegative.raw)
}
if (d0Form.bankCard.imgurl.uid) {
d0Form.bankCard.imgurl = await uploadOSS(d0Form.bankCard.imgurl.raw)
}
await updateAccount(d0Form)
ElMessage.success('提交成功')
} catch (error) {
console.log('d0提交表单error', error)
}
}
// 结算信息
async function merchBaseAccountAjax() {
try {
const res = await merchBaseAccount(route.query.id)
await d1BanknameChange(res.D1.bankCard.bankname, res.D1.bankCard.branchcity)
await d0BanknameChange(res.D1.bankCard.bankname, res.D1.bankCard.branchcity)
d1Form.bankCard = res.D1.bankCard
d1Form.idcard = res.D1.idCard
d0Form.bankCard = res.D0.bankCard
d0Form.idcard = res.D0.idCard
d1idcardRef1.value.pselectFile({ url: res.D1.idCard.imgpositive })
d1idcardRef2.value.pselectFile({ url: res.D1.idCard.imgnegative })
d1BankRef3.value.pselectFile({ url: res.D1.bankCard.imgurl })
d1AddressRef.value.setValue([res.D1.bankCard.branchProvinceCode, res.D1.bankCard.branchCityCode, res.D1.bankCard.branchAreaCode])
d0idcardRef1.value.pselectFile({ url: res.D0.idCard.imgpositive })
d0idcardRef2.value.pselectFile({ url: res.D0.idCard.imgnegative })
d0BankRef3.value.pselectFile({ url: res.D0.bankCard.imgurl })
d0AddressRef.value.setValue([res.D0.bankCard.branchProvinceCode, res.D0.bankCard.branchCityCode, res.D0.bankCard.branchAreaCode])
} catch (error) {
console.log('结算信息error:', error)
}
}
onMounted(() => {
merchBaseAccountAjax()
})
</script>
<style scoped lang="scss">
@import './common.scss';
</style>

View File

@@ -0,0 +1,279 @@
<!-- 商户基本信息组件 -->
<template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120" label-position="left">
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="merchantname" label="商户名称">
<el-input v-model="form.merchantname" placeholder="请输入商户名称" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item label="商户类型">
<el-input v-model="form.merchanttype" readonly placeholder="请输入商户类型" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="alias" label="商户简称">
<el-input v-model="form.alias" placeholder="请输入商户简称" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="contactname" label="商户联系人">
<el-input v-model="form.contactname" placeholder="请输入商户联系人" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="email" label="联系人邮箱">
<el-input v-model="form.email" placeholder="请输入联系人邮箱" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="contactmobile" label="联系人电话">
<el-input v-model="form.contactmobile" placeholder="请输入联系人电话" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="mcc" label="经营类目">
<el-input v-model="form.mccname" suffix-icon="ArrowDown" readonly placeholder="请选择经营类目"
@click="showDialog = true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="province" label="商户地址">
<address-card ref="addressRef" placeholder="请选择商户地址" style="width: 100%;" @change="selectBankAddress" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="address" label="详细地址">
<el-input v-model="form.address" placeholder="请输入详细地址" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="gutter">
<el-col :span="span">
<el-form-item prop="picUrl6" label="门头照">
<upload-card ref="uploadRef1" @selectFile="file => form.picUrl6 = file"
@removeFile="form.picUrl6 = ''" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="picUrl6" label="收银台照">
<upload-card ref="uploadRef2" @selectFile="file => form.picUrl8 = file"
@removeFile="form.picUrl8 = ''" />
</el-form-item>
</el-col>
<el-col :span="span">
<el-form-item prop="picUrl6" label="门店内场景照">
<upload-card ref="uploadRef3" @selectFile="file => form.picUrl9 = file"
@removeFile="form.picUrl9 = ''" />
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" @click="submitHandel">立即提交</el-button>
</el-form-item>
</el-form>
<el-dialog title="经营类目" v-model="showDialog" @open="mccOpen">
<el-space>
<el-input v-model="mccTable.keyWord" placeholder="请输入关键字搜索"></el-input>
<el-button type="primary" icon="Search" @click="mccOpen">搜索</el-button>
</el-space>
<div class="mt15">
<el-table :data="mccTable.list" v-loading="mccTable.loading">
<el-table-column prop="fId" label="id"></el-table-column>
<el-table-column prop="fMccCode" label="code"></el-table-column>
<el-table-column prop="fMccTxt" label="三级类目名称"></el-table-column>
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button type="primary" size="small" @click="selectMcc(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="mccTable.pageNum" v-model:page-size="mccTable.pageSize" :page-size="mccTable.pageSize"
:page-sizes="[10, 20, 30, 50]" :total="mccTable.total" @size-change="paginationChange"
@current-change="paginationChange" />
</div>
</el-dialog>
</template>
<script setup>
import uploadCard from './uploadCard.vue'
import addressCard from '@/components/addressCard.vue'
import { ElMessage } from 'element-plus'
import { uploadOSS } from '@/api/home.js'
import { mccPageData, merchBaseInfo, updateMerchantInformation } from '@/api/shop.js'
import { useRoute } from 'vue-router'
import { reactive } from 'vue';
import { ElDialog } from 'element-plus';
const route = useRoute()
const span = ref(8)
const gutter = ref(50)
const formRef = ref(null)
const addressRef = ref(null)
const uploadRef1 = ref(null)
const uploadRef2 = ref(null)
const uploadRef3 = ref(null)
const form = reactive({
id: '',
userid: route.query.id,
merchantname: '',
merchanttype: '',
merchantcode: route.query.merchantcode,
alias: '',
contactname: '',
email: '',
contactmobile: '',
mcc: '',
mccname: '',
province: '',
provinceCode: '',
city: '',
cityCode: '',
district: '',
districtCode: '',
address: '',
picUrl6: '',
picUrl8: '',
picUrl9: '',
picUrl101: '',
picUrl102: ''
})
const rules = reactive({})
// 获取省市区
function selectBankAddress(e) {
form.province = e[0].label
form.city = e[1].label
form.district = e[2].label
form.provinceCode = e[0].code
form.cityCode = e[1].code
form.districtCode = e[2].code
}
// 立即提交
async function submitHandel() {
await formRef.value.validate(async (vaild) => {
if (vaild) {
if (form.picUrl6.uid) {
form.picUrl6 = await uploadOSS(form.picUrl6.raw)
}
if (form.picUrl8.uid) {
form.picUrl8 = await uploadOSS(form.picUrl8.raw)
}
if (form.picUrl9.uid) {
form.picUrl9 = await uploadOSS(form.picUrl9.raw)
}
await updateMerchantInformation(form)
ElMessage.success('修改成功')
}
})
}
// 获取经营类目
const showDialog = ref(false)
const mccTable = reactive({
loading: true,
keyWord: '',
list: [],
total: 0,
pageNum: 1,
pageSize: 10
})
function mccOpen() {
mccTable.pageNum = 1
paginationChange()
}
function paginationChange() {
mccTable.loading = true
mccPageDataAjax()
}
async function mccPageDataAjax() {
try {
const res = await mccPageData({
current: mccTable.pageNum,
size: mccTable.pageSize,
keyWord: mccTable.keyWord
})
mccTable.loading = false
mccTable.list = res.list
mccTable.total = res.total
} catch (error) {
console.log('获取经营类目err===', error)
}
}
// 选择mcc
function selectMcc(row) {
form.mccname = `${row.fMccTxt}[${row.fMccCode}]`
form.mcc = row.fMccCode
showDialog.value = false
}
// 商户基本信息
async function merchBaseInfoAjax() {
try {
const res = await merchBaseInfo(route.query.id)
const m = {
1: '小微',
2: '个体',
3: '企业'
}
form.id = res.merchantBaseInfo.id
form.merchantname = res.merchantBaseInfo.merchantname
form.merchanttype = m[res.merchantBaseInfo.merchanttype]
form.alias = res.merchantBaseInfo.alias
form.contactname = res.merchantBaseInfo.contactname
form.email = res.merchantBaseInfo.email
form.contactmobile = res.merchantBaseInfo.contactmobile
form.mcc = res.merchantBaseInfo.mcc
form.mccname = `${res.merchantBaseInfo.mccname}[${res.merchantBaseInfo.mcc}]`
form.province = res.merchantBaseInfo.province
form.city = res.merchantBaseInfo.city
form.district = res.merchantBaseInfo.district
form.address = res.merchantBaseInfo.address
addressRef.value.setValue([res.merchantBaseInfo.provinceCode, res.merchantBaseInfo.cityCode, res.merchantBaseInfo.districtCode])
form.picUrl6 = res.merchantImagesList.find(item => item.photoType == '06').picurl
uploadRef1.value.pselectFile({ url: form.picUrl6 })
form.picUrl8 = res.merchantImagesList.find(item => item.photoType == '08').picurl
uploadRef2.value.pselectFile({ url: form.picUrl8 })
form.picUrl9 = res.merchantImagesList.find(item => item.photoType == '09').picurl
uploadRef3.value.pselectFile({ url: form.picUrl9 })
} catch (error) {
console.log('商户基本信息err===', error)
}
}
onMounted(() => {
merchBaseInfoAjax()
mccPageDataAjax()
})
</script>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,131 @@
<template>
<div class="card">
<el-space>
<el-input v-model="tableOptions.phone" placeholder="请输入手机号" style="width: 200px;" />
<el-input v-model="tableOptions.name" placeholder="请输入姓名" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
<el-button icon="RefreshRight" @click="resizeTable">重置</el-button>
</el-space>
<div class="table mt15">
<el-table ref="table" :data="tableOptions.list" border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="userId" label="id"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="phone" label="电话"></el-table-column>
<el-table-column prop="status" label="状态">
<template #default="scope">
<el-tag type="info" disable-transitions round v-if="scope.row.status == 0">申请中</el-tag>
<el-tag type="success" disable-transitions round v-if="scope.row.status == 1">已通过</el-tag>
<el-tag type="danger" disable-transitions round v-if="scope.row.status == 5">已驳回</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
<el-text>{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</el-text>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template #default="scope">
<template v-if="scope.row.status == 0">
<el-popconfirm title="是否通过审核?" width="200" confirm-button-text="通过" cancel-button-text="驳回"
@cancel="checkHandle(scope.row, 5)" @confirm="checkHandle(scope.row, 1)">
<template #reference>
<el-button type="primary" size="small" icon="EditPen">待审核</el-button>
</template>
</el-popconfirm>
</template>
<template v-else>
<el-button type="default" size="small" icon="EditPen" disabled v-if="scope.row.status == 1">
已通过
</el-button>
<el-button type="default" size="small" icon="EditPen" disabled v-if="scope.row.status == 5">
已驳回
</el-button>
</template>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import { dayjs, ElMessage } from 'element-plus';
import { getUserMark, updateUserMark } from '@/api/shop.js'
const table = ref(null)
// 表格参数
const tableOptions = reactive({
loading: true,
phone: '',
name: '',
list: [],
total: 0,
pageNum: 1,
pageSize: 10
})
// 重置表格
function resizeTable() {
tableOptions.phone = ''
tableOptions.name = ''
searchHandle()
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
getUserMarkAjax()
}
// 审核
async function checkHandle(row, type) {
try {
await updateUserMark({
status: type,
id: row.userId,
remark: ''
})
ElMessage.success('提交成功')
resizeTable()
} catch (error) {
}
}
// 获取创客审核列表
async function getUserMarkAjax() {
try {
const res = await getUserMark({
phone: tableOptions.phone,
name: tableOptions.name,
pageNum: tableOptions.pageNum,
pageSize: tableOptions.pageSize
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
table.value.setScrollTop(0)
} catch (error) {
}
}
onMounted(() => {
getUserMarkAjax()
})
</script>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,333 @@
<template>
<div class="card">
<div class="pb15" v-permission="['FO']">
<el-button type="primary" icon="Plus" @click="showDialog = true">添加小机构</el-button>
</div>
<el-space>
<el-input placeholder="请输入机构代码搜索" v-model="tableOptions.agencyCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border v-loading="tableOptions.loading">
<el-table-column prop="id" label="机构id"></el-table-column>
<el-table-column prop="agencyName" label="机构名称">
<template #default="scope">
<el-text>{{ scope.row.agencyName || scope.row.agencyCode }}</el-text>
</template>
</el-table-column>
<el-table-column prop="agencyCode" label="机构代码"></el-table-column>
<el-table-column prop="current_fee" label="推广费率">
<template #default="scope" v-permission="['FO']">
<el-link icon="EditPen" type="primary" @click="eitorFeeHandle(scope.row)">
{{ scope.row.current_fee }}%
</el-link>
</template>
</el-table-column>
<el-table-column prop="parentLoginName" label="上级机构代码"></el-table-column>
<el-table-column prop="sumConsumeFee" label="总流水">
<template #default="scope">
<el-text>{{ scope.row.sumConsumeFee.toFixed(2) }}</el-text>
</template>
</el-table-column>
<el-table-column prop="yestedayConsumeFee" label="今日流水"></el-table-column>
<el-table-column prop="sumfansShareMoney" label="总收益">
<template #default="scope">
<el-link type="primary" icon="search" @click="showTotalEarnings(scope.row.id)">
{{ scope.row.sumfansShareMoney }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="yestedayShareMoney" label="今日收益"></el-table-column>
<el-table-column prop="sumAccount" label="商家数量"></el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" type="primary" icon="DataLine"
@click="checkChartHandle(scope.row.id)">详细数据</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog title="修改推广费率" v-model="showFeeDialog" @closed="feeDialogClosed">
<el-form ref="formFeeRef" :model="feeForm" :rules="feeRules" label-width="100">
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="feeForm.fee">
<template #append>%</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showFeeDialog = false">取消</el-button>
<el-button type="primary" :loading="showFeeLoading" @click="feeSubmitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<el-dialog title="添加小机构" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item label="机构类型">
<el-select v-model="form.userType" disabled>
<el-option :key="item.type_code" :label="item.type_name" :value="item.type_code"
v-for="item in organizationList" key="item.type_code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="agencyName" label="机构名称">
<el-input placeholder="请输入机构名称" v-model="form.agencyName" />
</el-form-item>
<el-form-item prop="angencyCode" label="机构代码">
<el-input placeholder="请输入机构代码" :maxlength="11" show-word-limit v-model="form.angencyCode" />
</el-form-item>
<el-form-item prop="passowrd" label="密码">
<el-input type="password" show-password placeholder="请输入密码" :maxlength="11" v-model="form.passowrd" />
</el-form-item>
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="form.fee">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item prop="phone" label="联系方式">
<el-input placeholder="请输入手机号" v-model="form.phone" />
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<totalEarnings ref="totalEarningsRef" />
<el-dialog title="详细数据" width="90%" v-model="showChartCard">
<chart-card v-if="showChartCard" :user-id="userId" />
</el-dialog>
</div>
</template>
<script setup>
import { addAgency, queryAgency, modifyFee } from '@/api/organization.js'
import { ElMessage } from 'element-plus'
import { validPhone, organizationList, addOrganizations } from '@/utils'
import { onMounted, reactive } from 'vue';
import { useUser } from '@/store/user.js'
// 图表相关
import chartCard from '@/components/chartCard.vue';
const showChartCard = ref(false)
const userId = ref()
function checkChartHandle(id) {
userId.value = id
showChartCard.value = true
}
// totalEarnings组件相关
import totalEarnings from '@/components/totalEarnings.vue';
const totalEarningsRef = ref('')
function showTotalEarnings(parent_user_id) {
totalEarningsRef.value.show(parent_user_id)
}
const storeUser = useUser()
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const showFeeDialog = ref(false)
const showFeeLoading = ref(false)
// 获取添加小机构表单实例
let formRef = ref(null)
// 获取修改费率表单实例
let formFeeRef = ref(null)
// 创建表单
const form = reactive({
agencyName: '',
angencyCode: '',
passowrd: '',
fee: '',
userType: addOrganizations[storeUser.userInfo.userType],
phone: ''
})
// 创建修改费率表单
const feeForm = reactive({
id: '',
fee: ''
})
const feeRules = reactive({
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 自定义校验密码
function passowrdValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (value.length < 6) {
return callback(new Error('密码最少6位'))
} else {
callback()
}
}
// 自定义校验手机号
function phoneValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (!validPhone(value)) {
return callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
// 创建form校验规则
const rules = reactive({
agencyName: [
{
required: true,
message: '',
trigger: 'blur'
}
],
angencyCode: [
{
required: true,
message: '',
trigger: 'blur'
}
],
passowrd: [
{
required: true,
validator: passowrdValidate,
trigger: 'blur'
}
],
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
],
phone: [
{
required: true,
validator: phoneValidate,
trigger: 'blur'
}
]
})
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
}
// 修改费率关闭
function feeDialogClosed() {
formFeeRef.value.resetFields()
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild, fields) => {
if (vaild) {
try {
formLoading.value = true
await addAgency(form)
formLoading.value = false
showDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
// 提交修改费率
async function feeSubmitHandle() {
await formFeeRef.value.validate(async (vaild) => {
if (vaild) {
try {
showFeeLoading.value = true
await modifyFee(feeForm)
showFeeLoading.value = false
showFeeDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
showFeeLoading.value = false
}
}
})
}
// 修改费率
function eitorFeeHandle(row) {
feeForm.id = row.id
feeForm.fee = row.current_fee
showFeeDialog.value = true
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryAgencyHandle()
}
// 获取机构列表
async function queryAgencyHandle() {
try {
const res = await queryAgency({
agencyCode: tableOptions.agencyCode,
pageNum: tableOptions.pageNum,
pageSzie: tableOptions.pageSzie,
userType: 'SO',
isExtend: ''
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
} catch (error) { }
}
onMounted(() => {
queryAgencyHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 310px);
}
</style>

View File

@@ -0,0 +1,339 @@
<template>
<div class="card">
<!-- <el-row>
<el-space>
<el-button type="primary" icon="Plus" @click="showDialog = true" v-permission="['SO']">添加大机构</el-button>
</el-space>
</el-row> -->
<el-space>
<el-input placeholder="请输入机构代码搜索" v-model="tableOptions.agencyCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="机构id"></el-table-column>
<el-table-column prop="agencyName" label="代理名称">
<template #default="scope">
<el-text>{{ scope.row.agencyName || scope.row.agencyCode }}</el-text>
</template>
</el-table-column>
<el-table-column prop="agencyCode" label="机构代码"></el-table-column>
<el-table-column prop="current_fee" label="推广费率">
<template #default="scope">
<el-text>{{ scope.row.current_fee }}%</el-text>
</template>
</el-table-column>
<el-table-column prop="parentLoginName" label="上级机构代码"></el-table-column>
<el-table-column prop="sumConsumeFee" label="总流水">
<template #default="scope">
<el-text>{{ scope.row.sumConsumeFee.toFixed(2) }}</el-text>
</template>
</el-table-column>
<el-table-column prop="yestedayConsumeFee" label="今日流水"></el-table-column>
<el-table-column prop="sumfansShareMoney" label="总收益">
<template #default="scope">
<el-link type="primary" icon="search" @click="showTotalEarnings(scope.row.id)">
{{ scope.row.sumfansShareMoney }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="yestedayShareMoney" label="今日收益"></el-table-column>
<el-table-column prop="sumAccount" label="商家数量"></el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" type="primary" icon="DataLine"
@click="checkChartHandle(scope.row.id)">详细数据</el-button>
</template>
</el-table-column>
<!-- <el-table-column label="操作">
<template #default="scope">
<el-button type="primary" size="small" icon="EditPen" @click="eitorFeeHandle(scope.row)"
v-permission="['SO']">修改费率</el-button>
</template>
</el-table-column> -->
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog title="修改推广费率" v-model="showFeeDialog" @closed="feeDialogClosed">
<el-form ref="formFeeRef" :model="feeForm" :rules="feeRules" label-width="100">
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="feeForm.fee">
<template #append>%</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showFeeDialog = false">取消</el-button>
<el-button type="primary" :loading="showFeeLoading" @click="feeSubmitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<el-dialog title="添加大机构" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item label="机构类型">
<el-select v-model="form.userType" disabled>
<el-option :key="item.type_code" :label="item.type_name" :value="item.type_code"
v-for="item in organizationList" key="item.type_code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="agencyName" label="机构名称">
<el-input placeholder="请输入机构名称" v-model="form.agencyName" />
</el-form-item>
<el-form-item prop="angencyCode" label="机构代码">
<el-input placeholder="请输入机构代码" :maxlength="11" show-word-limit v-model="form.angencyCode" />
</el-form-item>
<el-form-item prop="passowrd" label="密码">
<el-input type="password" show-password placeholder="请输入密码" :maxlength="11" v-model="form.passowrd" />
</el-form-item>
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="form.fee">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item prop="phone" label="联系方式">
<el-input placeholder="请输入手机号" v-model="form.phone" />
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<totalEarnings ref="totalEarningsRef" />
<el-dialog title="详细数据" width="90%" v-model="showChartCard">
<chart-card v-if="showChartCard" :user-id="userId" />
</el-dialog>
</div>
</template>
<script setup>
import { addAgency, queryAgency, modifyFee } from '@/api/organization.js'
import { ElMessage } from 'element-plus'
import { validPhone, organizationList, addOrganizations } from '@/utils'
import { onMounted, reactive } from 'vue';
import { useUser } from '@/store/user.js'
// 图表相关
import chartCard from '@/components/chartCard.vue';
const showChartCard = ref(false)
const userId = ref()
function checkChartHandle(id) {
userId.value = id
showChartCard.value = true
}
// totalEarnings组件相关
import totalEarnings from '@/components/totalEarnings.vue';
const totalEarningsRef = ref('')
function showTotalEarnings(parent_user_id) {
totalEarningsRef.value.show(parent_user_id)
}
const storeUser = useUser()
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const showFeeDialog = ref(false)
const showFeeLoading = ref(false)
// 获取添加小机构表单实例
let formRef = ref(null)
// 获取修改费率表单实例
let formFeeRef = ref(null)
// 创建表单
const form = reactive({
agencyName: '',
angencyCode: '',
passowrd: '',
fee: '',
userType: addOrganizations[storeUser.userInfo.userType],
phone: ''
})
// 创建修改费率表单
const feeForm = reactive({
id: '',
fee: ''
})
const feeRules = reactive({
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 自定义校验密码
function passowrdValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (value.length < 6) {
return callback(new Error('密码最少6位'))
} else {
callback()
}
}
// 自定义校验手机号
function phoneValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (!validPhone(value)) {
return callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
// 创建form校验规则
const rules = reactive({
agencyName: [
{
required: true,
message: '',
trigger: 'blur'
}
],
angencyCode: [
{
required: true,
message: '',
trigger: 'blur'
}
],
passowrd: [
{
required: true,
validator: passowrdValidate,
trigger: 'blur'
}
],
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
],
phone: [
{
required: true,
validator: phoneValidate,
trigger: 'blur'
}
]
})
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
}
// 修改费率关闭
function feeDialogClosed() {
formFeeRef.value.resetFields()
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild, fields) => {
if (vaild) {
try {
formLoading.value = true
await addAgency(form)
formLoading.value = false
showDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
// 提交修改费率
async function feeSubmitHandle() {
await formFeeRef.value.validate(async (vaild) => {
if (vaild) {
try {
showFeeLoading.value = true
await modifyFee(feeForm)
showFeeLoading.value = false
showFeeDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
showFeeLoading.value = false
}
}
})
}
// 修改费率
function eitorFeeHandle(row) {
feeForm.id = row.id
feeForm.fee = row.current_fee
showFeeDialog.value = true
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryAgencyHandle()
}
// 获取机构列表
async function queryAgencyHandle() {
try {
const res = await queryAgency({
agencyCode: tableOptions.agencyCode,
pageNum: tableOptions.pageNum,
pageSzie: tableOptions.pageSzie,
userType: 'FB',
isExtend: ''
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
} catch (error) { }
}
onMounted(() => {
queryAgencyHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 310px);
}
</style>

View File

@@ -0,0 +1,167 @@
<template>
<div class="card">
<div class="nav_wrap">
<el-radio-group v-model="type">
<el-radio-button :label="item.type" v-for="item in navs" :key="item.type">{{ item.label }}</el-radio-button>
</el-radio-group>
</div>
<div class="container mt15">
<div class="compont_wrap">
<!-- <authentication v-if="type == 1" />
<shopInfo v-if="type == 2" />
<settleInfo v-if="type == 3" />
<aisleInfo v-if="type == 4" /> -->
<component :is="componentList[type]" />
</div>
<div class="shop_info">
<div class="header">
<el-text size="large">商户关联信息</el-text>
</div>
<div class="title_wrap">
<el-text>身份信息关联进件成功的商户数量</el-text>
</div>
<div class="content">
<div class="row">
<el-space>
<el-text>实名身份证</el-text>
<el-text type="warning" tag="ins">{{ authInfo.CertNoCount }}</el-text>
</el-space>
</div>
<div class="row">
<el-space>
<el-text>结算身份证</el-text>
<el-text type="warning" tag="ins">{{ authInfo.countMbiName }}</el-text>
</el-space>
</div>
<div class="row">
<el-space>
<el-text>同名商户</el-text>
<el-text type="warning" tag="ins">{{ authInfo.countAccountCount }}</el-text>
</el-space>
</div>
</div>
<div class="title_wrap">
<el-text>用户IP记录</el-text>
</div>
<div class="mt15">
<el-table :data="tableOptions.list" border height="200" v-loading="tableOptions.loading">
<el-table-column prop="id" label="ID"></el-table-column>
</el-table>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie" small
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { connectInfo } from '@/api/shop.js'
import authentication from './components/authentication.vue'
import shopInfo from './components/shopInfo.vue'
import settleInfo from './components/settleInfo.vue'
import aisleInfo from './components/aisleInfo.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const authInfo = ref({})
const type = ref(1)
const componentList = {
1: authentication,
2: shopInfo,
3: settleInfo,
4: aisleInfo
}
const navs = ref([
{
type: 1,
label: '实名认证信息'
},
{
type: 2,
label: '商户基本信息'
},
{
type: 3,
label: '结算信息'
},
{
type: 4,
label: '通道进件信息'
}
])
// 表格参数
const tableOptions = reactive({
loading: true,
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 分页回调
function paginationChange() {
tableOptions.loading = true
}
// 实名认证信息页面(实名个数)
async function connectInfoAjax() {
try {
const res = await connectInfo(route.query.id)
authInfo.value = res
} catch (error) {
console.log('实名认证信息页面error', error)
}
}
onMounted(() => {
tableOptions.loading = false
connectInfoAjax()
})
</script>
<style scoped lang="scss">
@import './components/common.scss';
.nav_wrap {
padding-bottom: 15px;
border-bottom: 1px solid #ececec;
}
.container {
display: flex;
.compont_wrap {
flex: 2;
padding-right: 20px;
}
.shop_info {
flex: 1;
.header {
padding-bottom: 14px;
}
.content {
padding: 14px 20px;
.row {
&:not(:first-child) {
margin-top: 14px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,542 @@
<template>
<div class="card">
<div class="data_row">
<div class="item">
<div class="icon">
<img class="img" src="@/assets/home_icon6.png">
</div>
<div class="info">
<div class="title">商家总数</div>
<div class="num">
<count-to :start-val="0" :end-val="topData.sumCountNum" :duration="1000" />
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="@/assets/home_icon7.png">
</div>
<div class="info">
<div class="title">认证商家</div>
<div class="num">
<count-to :start-val="0" :end-val="topData.countNum" :duration="1000" />
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="@/assets/home_icon8.png">
</div>
<div class="info">
<div class="title">未认证商家</div>
<div class="num">
<count-to :start-val="0" :end-val="topData.subNum" :duration="1000" />
</div>
</div>
</div>
<!-- <div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon2.png">
</div>
<div class="info">
<div class="title">总收益</div>
<div class="num">
<count-to :start-val="0" :decimals="2" :end-val="homeData.sumfansShareMoney" :duration="1000" />
<span class="i"></span>
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon3.png">
</div>
<div class="info">
<div class="title">今日收益</div>
<div class="num">
<count-to :start-val="0" :decimals="2" :end-val="homeData.yestedayShareMoney" :duration="1000" />
<span class="i"></span>
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="../assets/home_icon4.png">
</div>
<div class="info">
<div class="title">推广费率</div>
<div class="num">
{{ homeData.currentFee }}
<span class="i">%</span>
</div>
</div>
</div> -->
</div>
</div>
<div class="card mt15">
<el-space>
<el-input placeholder="请输入商户登录号" v-model="tableOptions.agencyCode" style="width: 200px;" />
<el-input placeholder="请输入商户号" v-model="tableOptions.merchantCode" style="width: 200px;" />
<el-input placeholder="请输入商户号" v-model="tableOptions.phone" style="width: 200px;" />
<el-input placeholder="请输入用户ID" v-model="tableOptions.reqUserId" style="width: 200px;" />
<el-select placeholder="请选择进件状态" v-model="tableOptions.status">
<el-option :value="0" label="待审核"></el-option>
<el-option :value="1" label="审核中"></el-option>
<el-option :value="2" label="审核失败"></el-option>
<el-option :value="3" label="审核通过"></el-option>
</el-select>
<el-select placeholder="请选择类型" v-model="tableOptions.merchantType">
<el-option :value="1" label="小微"></el-option>
<el-option :value="2" label="个体"></el-option>
<el-option :value="3" label="企业"></el-option>
</el-select>
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
<el-button icon="RefreshRight" @click="resizeTable">重置</el-button>
</el-space>
<div class="table mt15">
<el-table ref="table" :data="tableOptions.list" size="large" stripe border height="100%"
v-loading="tableOptions.loading">
<el-table-column prop="id" label="ID"></el-table-column>
<el-table-column prop="agencyName" label="商家名称">
<template #default="scope">
<el-text>{{ scope.row.agencyName || scope.row.agencyCode }}</el-text>
</template>
</el-table-column>
<!-- <el-table-column prop="current_fee" label="推广费率">
<template #default="scope">
<el-text type="info" v-if="scope.row.is_extend == 0"></el-text>
<el-text type="primary" v-else>{{ scope.row.current_fee }}%</el-text>
</template>
</el-table-column> -->
<!-- <el-table-column prop="sumConsumeFee" label="总流水">
<template #default="scope">
<el-text>{{ scope.row.sumConsumeFee.toFixed(2) }}</el-text>
</template>
</el-table-column> -->
<el-table-column prop="sumfansShareMoney" label="累计收款">
<template #default="scope">
<el-link type="primary" icon="search" @click="showTotalEarnings(scope.row.id)">
{{ scope.row.sumConsumeFee }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="yestedayConsumeFee" label="昨日收款"></el-table-column>
<el-table-column prop="sumfansShareMoney" label="累计收益"></el-table-column>
<el-table-column label="商户基本信息">
<template #default="scope">
<div class="column">
<el-text type="primary" size="small">{{ scope.row.merchantBaseInfo.merchantTypeName }}</el-text>
<el-text size="small">{{ scope.row.merchantCode }}</el-text>
<el-text type="success" size="small">{{ scope.row.merchantBaseInfo.alias }}</el-text>
</div>
</template>
</el-table-column>
<el-table-column label="进件审核状态" align="center">
<el-table-column label="随行付">
<template #default="scope">
<div class="column">
<el-text :type="filterData(scope.row.merchantChannel, 1).type" size="small">
{{ filterData(scope.row.merchantChannel, 1).text }}
</el-text>
<template v-if="filterData(scope.row.merchantChannel,
1).text != '-'">
<el-text size="small">
{{ filterData(scope.row.merchantChannel,
1).data.merchantId }}
</el-text>
<el-text type="info" size="small">
{{ dayjs(filterData(scope.row.merchantChannel,
1).data.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
</el-text>
</template>
</div>
</template>
</el-table-column>
<el-table-column label="银盛D1">
<template #default="scope">
<div class="column">
<el-text :type="filterData(scope.row.merchantChannel, 6).type" size="small">
{{ filterData(scope.row.merchantChannel, 6).text }}
</el-text>
<template v-if="filterData(scope.row.merchantChannel,
6).text != '-'">
<el-text size="small">
{{ filterData(scope.row.merchantChannel,
6).data.merchantId }}
</el-text>
<el-text type="info" size="small">
{{ dayjs(filterData(scope.row.merchantChannel,
6).data.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
</el-text>
</template>
</div>
</template>
</el-table-column>
<el-table-column label="银盛">
<template #default="scope">
<div class="column">
<el-text :type="filterData(scope.row.merchantChannel, 4).type" size="small">
{{ filterData(scope.row.merchantChannel, 4).text }}
</el-text>
<template v-if="filterData(scope.row.merchantChannel,
4).text != '-'">
<el-text size="small">
{{ filterData(scope.row.merchantChannel,
4).data.merchantId }}
</el-text>
<el-text type="info" size="small">
{{ dayjs(filterData(scope.row.merchantChannel,
4).data.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
</el-text>
</template>
</div>
</template>
</el-table-column>
<el-table-column label="拉卡拉">
<template #default="scope">
<div class="column">
<el-text :type="filterData(scope.row.merchantChannel, 5).type" size="small">
{{ filterData(scope.row.merchantChannel, 5).text }}
</el-text>
<template v-if="filterData(scope.row.merchantChannel,
5).text != '-'">
<el-text size="small">
{{ filterData(scope.row.merchantChannel,
5).data.merchantId }}
</el-text>
<el-text type="info" size="small">
{{ dayjs(filterData(scope.row.merchantChannel,
5).data.updateTime).format('YYYY-MM-DD HH:mm:ss') }}
</el-text>
</template>
</div>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="创客等级" align="center">
<template #default="scope">
<el-tag type="info" disable-transitions v-if="scope.row.is_extend == 0">普通商户</el-tag>
<el-tag type="success" disable-transitions v-if="scope.row.is_extend == 1">初级创客</el-tag>
<el-tag type="warning" disable-transitions v-if="scope.row.is_extend == 2">高级创客</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template #default="scope">
<RouterLink
:to="{ name: 'shop_detail', query: { id: scope.row.id, name: scope.row.agencyName, account: scope.row.agencyCode, merchantcode: scope.row.merchantCode } }">
<el-button type="primary" size="small" icon="Search" v-permission="['MG']">
详情
</el-button>
</RouterLink>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog v-model="showDialog" title="累计收益" width="80%">
<el-space>
<el-input placeholder="请输入订单号搜索" v-model="dialogTableOptions.orderNumber" style="width: 200px;" />
<el-input placeholder="请输入商户号搜索" v-model="dialogTableOptions.merchantCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="dialogSearchHandle">搜索</el-button>
</el-space>
<div class="mt15">
<el-table :data="dialogTableOptions.list" v-loading="dialogTableOptions.loading">
<el-table-column prop="orderNumber" label="订单号"></el-table-column>
<el-table-column prop="merchantCode" label="商户号"></el-table-column>
<el-table-column prop="consumeFee" label="交易金额"></el-table-column>
<el-table-column prop="current_fee" label="推广费率">
<template #default="scope">
<el-text type="primary">{{ scope.row.currentFee }}%</el-text>
</template>
</el-table-column>
<el-table-column prop="loginName" label="名称">
<template #default="scope">
<el-text>{{ scope.row.loginName }}</el-text>
<el-tag disable-transitions style="margin-left: 8px;">{{ typeNames[scope.row.typeCode]
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="merchantName" label="商户名称">
</el-table-column>
<el-table-column prop="createDt" label="时间">
<template #default="scope">
{{ dayjs(scope.row.createDt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper"
v-model:current-page="dialogTableOptions.pageNum" v-model:page-size="dialogTableOptions.pageSzie"
:page-size="dialogTableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]"
:total="dialogTableOptions.total" @size-change="dialogPaginationChange"
@current-change="dialogPaginationChange" />
</div>
</el-dialog>
</div>
</template>
<script setup>
import { queryCustormerFlow, queryCustormSum } from '@/api/shop.js'
import { onMounted, reactive } from 'vue';
import { dayjs } from 'element-plus';
import { typeNames } from '@/utils/index.js'
import { queryOrder } from '@/api/organization.js'
const table = ref('')
const showDialog = ref(false)
// 表格参数
const dialogTableOptions = reactive({
loading: true,
reqUserId: '', // 上级id
orderNumber: '', // 订单号
merchantCode: '', // 商户号
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 搜索
function dialogSearchHandle() {
dialogTableOptions.pageNum = 1;
dialogPaginationChange()
}
// 分页回调
function dialogPaginationChange() {
dialogTableOptions.loading = true
getTableDate()
}
// 获取机构列表
async function getTableDate() {
try {
const res = await queryOrder({
reqUserId: dialogTableOptions.reqUserId,
orderNumber: dialogTableOptions.orderNumber,
merchantCode: dialogTableOptions.merchantCode,
pageNum: dialogTableOptions.pageNum,
pageSzie: dialogTableOptions.pageSzie
})
dialogTableOptions.loading = false
dialogTableOptions.list = res.list
dialogTableOptions.total = res.total
} catch (error) { }
}
// 显示收益明细
function showTotalEarnings(parent_user_id) {
dialogTableOptions.reqUserId = parent_user_id
showDialog.value = true
getTableDate()
}
// ===================
// 顶部数据
const topData = reactive({
countNum: 0, // 认证数量
subNum: 0, // 未认证数量
sumCountNum: 0, // 总数
})
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '', // 商户登录号
merchantCode: '', // 商户号
phone: '',
status: '', // 进件状态。0或无、待审核1、审核中 2、审核失败 3、审核通过
merchantType: '', // 1:小微 2:个体 3:企业
reqUserId: '', // 用户id
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 重置表格
function resizeTable() {
tableOptions.agencyCode = ''
tableOptions.merchantCode = ''
tableOptions.status = ''
tableOptions.merchantType = ''
tableOptions.reqUserId = ''
searchHandle()
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryCustormerFlowHandle()
}
// 获取机构列表
async function queryCustormerFlowHandle() {
try {
const res = await queryCustormerFlow({
agencyCode: tableOptions.agencyCode,
merchantCode: tableOptions.merchantCode,
phone: tableOptions.phone,
status: tableOptions.status,
merchantType: tableOptions.merchantType,
reqUserId: tableOptions.reqUserId,
pageNum: tableOptions.pageNum,
pageSzie: tableOptions.pageSzie,
userType: 'MC',
isExtend: 'shop'
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
table.value.setScrollTop(0)
} catch (error) { }
}
// 商户列表数据统计
const queryCustormSumAjax = async () => {
try {
const res = await queryCustormSum()
topData.countNum = res.countNum
topData.subNum = res.subNum
topData.sumCountNum = res.sumCountNum
} catch (error) { }
}
// 过滤进件数据
function filterData(arr, type) {
const m = {
0: {
text: '待审核',
type: 'info',
data: ''
},
1: {
text: '审核中',
type: 'warning',
data: ''
},
2: {
text: '审核失败',
type: 'danger',
data: ''
},
3: {
text: '审核通过',
type: 'success',
data: ''
},
4: {
text: '-',
type: 'info',
data: ''
}
}
const res = arr.find(item => item.channel == type).baseInfo;
if (!!res && m[res.status]) {
m[res.status].data = res
}
return (res ? m[res.status] : m[4]) || m[4]
}
onMounted(() => {
queryCustormerFlowHandle()
queryCustormSumAjax()
})
</script>
<style>
.el-text {
align-self: flex-start;
}
</style>
<style scoped lang="scss">
.column {
display: flex;
flex-direction: column;
}
.table {
height: calc(100vh - 435px);
}
.data_row {
display: flex;
padding: 12px 0;
.item {
flex: 1;
display: flex;
padding-left: 50px;
&:not(:last-child) {
position: relative;
&::after {
content: "";
height: 100%;
border-right: 1px solid #ececec;
position: absolute;
top: 0;
right: 0;
}
}
.icon {
$size: 55px;
width: $size;
height: $size;
border-radius: 50%;
background-color: #F2F3F5;
display: flex;
justify-content: center;
align-items: center;
.img {
$size: 30px;
width: $size;
height: $size;
object-fit: contain;
}
}
.info {
flex: 1;
padding-left: 20px;
display: flex;
flex-direction: column;
justify-content: center;
.title {
font-size: 14px;
color: #666;
font-weight: 300;
}
.num {
font-size: 24px;
font-weight: bold;
padding-top: 10px;
.i {
font-size: 12px;
position: relative;
bottom: 1px;
right: -4px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,339 @@
<template>
<div class="card">
<!-- <el-row>
<el-space>
<el-button type="primary" icon="Plus" @click="showDialog = true" v-permission="['SO']">添加大机构</el-button>
</el-space>
</el-row> -->
<el-space>
<el-input placeholder="请输入机构代码搜索" v-model="tableOptions.agencyCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="机构id"></el-table-column>
<el-table-column prop="agencyName" label="机构名称">
<template #default="scope">
<el-text>{{ scope.row.agencyName || scope.row.agencyCode }}</el-text>
</template>
</el-table-column>
<el-table-column prop="agencyCode" label="机构代码"></el-table-column>
<el-table-column prop="current_fee" label="推广费率">
<template #default="scope">
<el-text>{{ scope.row.current_fee }}%</el-text>
</template>
</el-table-column>
<el-table-column prop="parentLoginName" label="上级机构代码"></el-table-column>
<el-table-column prop="sumConsumeFee" label="总流水">
<template #default="scope">
<el-text>{{ scope.row.sumConsumeFee.toFixed(2) }}</el-text>
</template>
</el-table-column>
<el-table-column prop="yestedayConsumeFee" label="今日流水"></el-table-column>
<el-table-column prop="sumfansShareMoney" label="总收益">
<template #default="scope">
<el-link type="primary" icon="search" @click="showTotalEarnings(scope.row.id)">
{{ scope.row.sumfansShareMoney }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="yestedayShareMoney" label="今日收益"></el-table-column>
<el-table-column prop="sumAccount" label="商家数量"></el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" type="primary" icon="DataLine"
@click="checkChartHandle(scope.row.id)">详细数据</el-button>
</template>
</el-table-column>
<!-- <el-table-column label="操作">
<template #default="scope">
<el-button type="primary" size="small" icon="EditPen" @click="eitorFeeHandle(scope.row)"
v-permission="['SO']">修改费率</el-button>
</template>
</el-table-column> -->
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog title="修改推广费率" v-model="showFeeDialog" @closed="feeDialogClosed">
<el-form ref="formFeeRef" :model="feeForm" :rules="feeRules" label-width="100">
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="feeForm.fee">
<template #append>%</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showFeeDialog = false">取消</el-button>
<el-button type="primary" :loading="showFeeLoading" @click="feeSubmitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<el-dialog title="添加大机构" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item label="机构类型">
<el-select v-model="form.userType" disabled>
<el-option :key="item.type_code" :label="item.type_name" :value="item.type_code"
v-for="item in organizationList" key="item.type_code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="agencyName" label="机构名称">
<el-input placeholder="请输入机构名称" v-model="form.agencyName" />
</el-form-item>
<el-form-item prop="angencyCode" label="机构代码">
<el-input placeholder="请输入机构代码" :maxlength="11" show-word-limit v-model="form.angencyCode" />
</el-form-item>
<el-form-item prop="passowrd" label="密码">
<el-input type="password" show-password placeholder="请输入密码" :maxlength="11" v-model="form.passowrd" />
</el-form-item>
<el-form-item prop="fee" label="推广费率">
<el-input placeholder="请输入推广费率" v-model="form.fee">
<template #append>%</template>
</el-input>
</el-form-item>
<el-form-item prop="phone" label="联系方式">
<el-input placeholder="请输入手机号" v-model="form.phone" />
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<totalEarnings ref="totalEarningsRef" />
<el-dialog title="详细数据" width="90%" v-model="showChartCard">
<chart-card v-if="showChartCard" :user-id="userId" />
</el-dialog>
</div>
</template>
<script setup>
import { addAgency, queryAgency, modifyFee } from '@/api/organization.js'
import { ElMessage } from 'element-plus'
import { validPhone, organizationList, addOrganizations } from '@/utils'
import { onMounted, reactive } from 'vue';
import { useUser } from '@/store/user.js'
// 图表相关
import chartCard from '@/components/chartCard.vue';
const showChartCard = ref(false)
const userId = ref()
function checkChartHandle(id) {
userId.value = id
showChartCard.value = true
}
// totalEarnings组件相关
import totalEarnings from '@/components/totalEarnings.vue';
const totalEarningsRef = ref('')
function showTotalEarnings(parent_user_id) {
totalEarningsRef.value.show(parent_user_id)
}
const storeUser = useUser()
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const showFeeDialog = ref(false)
const showFeeLoading = ref(false)
// 获取添加小机构表单实例
let formRef = ref(null)
// 获取修改费率表单实例
let formFeeRef = ref(null)
// 创建表单
const form = reactive({
agencyName: '',
angencyCode: '',
passowrd: '',
fee: '',
userType: addOrganizations[storeUser.userInfo.userType],
phone: ''
})
// 创建修改费率表单
const feeForm = reactive({
id: '',
fee: ''
})
const feeRules = reactive({
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 自定义校验密码
function passowrdValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (value.length < 6) {
return callback(new Error('密码最少6位'))
} else {
callback()
}
}
// 自定义校验手机号
function phoneValidate(rule, value, callback) {
if (!value) {
return callback(new Error(''))
} else if (!validPhone(value)) {
return callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
// 创建form校验规则
const rules = reactive({
agencyName: [
{
required: true,
message: '',
trigger: 'blur'
}
],
angencyCode: [
{
required: true,
message: '',
trigger: 'blur'
}
],
passowrd: [
{
required: true,
validator: passowrdValidate,
trigger: 'blur'
}
],
fee: [
{
required: true,
message: '',
trigger: 'blur'
}
],
phone: [
{
required: true,
validator: phoneValidate,
trigger: 'blur'
}
]
})
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
}
// 修改费率关闭
function feeDialogClosed() {
formFeeRef.value.resetFields()
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild, fields) => {
if (vaild) {
try {
formLoading.value = true
await addAgency(form)
formLoading.value = false
showDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
// 提交修改费率
async function feeSubmitHandle() {
await formFeeRef.value.validate(async (vaild) => {
if (vaild) {
try {
showFeeLoading.value = true
await modifyFee(feeForm)
showFeeLoading.value = false
showFeeDialog.value = false
ElMessage.success('添加成功')
paginationChange()
} catch (error) {
showFeeLoading.value = false
}
}
})
}
// 修改费率
function eitorFeeHandle(row) {
feeForm.id = row.id
feeForm.fee = row.current_fee
showFeeDialog.value = true
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryAgencyHandle()
}
// 获取机构列表
async function queryAgencyHandle() {
try {
const res = await queryAgency({
agencyCode: tableOptions.agencyCode,
pageNum: tableOptions.pageNum,
pageSzie: tableOptions.pageSzie,
userType: 'SB',
isExtend: ''
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
} catch (error) { }
}
onMounted(() => {
queryAgencyHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 310px);
}
</style>

View File

@@ -0,0 +1,14 @@
<template>
<div class="container">
<textarea v-size-ob="ob" cols="30" rows="10"></textarea>
</div>
</template>
<script setup>
function ob(size) {
console.log('🎨 size >>> ', size)
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,45 @@
<template>
<div class="container">
<el-button type="primary" @click="set">添加水印</el-button>
<el-button type="primary" @click="remove">移除水印</el-button>
<el-button type="primary" @click="dialogVisible = true">自定义水印</el-button>
<el-dialog v-model="dialogVisible" title="温馨提示" width="500px">
<el-input v-model="text" placeholder="请填写自定义水印" />
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="custom">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import watermark from "@/utils/watermark.js";
function set() {
watermark.set();
}
function remove() {
watermark.remove();
}
let text = ref("Vue3 ElePlus Admin");
let dialogVisible = ref(false);
function custom() {
watermark.set(text.value);
dialogVisible.value = false;
}
</script>
<style lang="scss" scoped>
.container {
display: flex;
align-items: center;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 10px;
}
</style>

View File

@@ -0,0 +1,305 @@
<template>
<div class="card">
<el-space>
<el-button type="primary" icon="Plus" @click="addHandle">添加推广图</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="ID"></el-table-column>
<el-table-column prop="code" label="CODE"></el-table-column>
<el-table-column prop="name" label="名字"></el-table-column>
<el-table-column label="状态" width="80">
<template #default="scope">
<el-tag type="success" disable-transitions v-if="scope.row.type == 1">开启</el-tag>
<el-tag type="warning" disable-transitions v-if="scope.row.type == 0">关闭</el-tag>
</template>
</el-table-column>
<el-table-column label="机型状态" width="120">
<template #default="scope">
<div class="mode_wrap">
<el-tag type="success" disable-transitions v-if="scope.row.android == 1">安卓开启</el-tag>
<el-tag type="warning" disable-transitions v-if="scope.row.android == 0">安卓关闭</el-tag>
<div class="height"></div>
<el-tag type="success" disable-transitions v-if="scope.row.ios == 1">IOS开启</el-tag>
<el-tag type="warning" disable-transitions v-if="scope.row.ios == 0">IOS关闭</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="图片">
<template #default="scope">
<el-image style="width: 50px; height: 50px" :src="scope.row.content" preview-teleported
hide-on-click-modal :preview-src-list="[scope.row.content]" fit="cover">
</el-image>
</template>
</el-table-column>
<el-table-column prop="updateTime" label="时间">
<template #default="scope">
{{ dayjs(scope.row.updateTime).format('YYYY/MM/DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="140">
<template #default="scope">
<el-button type="primary" size="small" icon="EditPen"
@click="editorHandle(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
<el-dialog :title="type == 1 ? '添加推广图' : '编辑推广图'" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="140">
<el-form-item prop="code" label="CODE" v-if="type == 1">
<el-input placeholder="请输入图片code" v-model="form.code" />
</el-form-item>
<el-form-item prop="name" label="图片名称" v-if="type == 1">
<el-input placeholder="请输入图片名称" v-model="form.name" />
</el-form-item>
<el-form-item prop="type" label="是否开启" v-if="type == 2">
<el-radio-group v-model="form.type">
<el-radio label="1">开启</el-radio>
<el-radio label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="android" label="安卓是否开启" v-if="type == 2 && form.type == 1">
<el-radio-group v-model="form.android">
<el-radio label="1">开启</el-radio>
<el-radio label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="ios" label="IOS是否开启" v-if="type == 2 && form.type == 1">
<el-radio-group v-model="form.ios">
<el-radio label="1">开启</el-radio>
<el-radio label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="content" label="图片url">
<el-upload ref="uploadRef" v-model:file-list="fileList" :limit="1" :on-exceed="handleExceed"
list-type="picture" :auto-upload="false" @change="selectFile" @remove="removeFile">
<template #trigger>
<el-button type="primary" icon="Picture">选择图片</el-button>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
</template>
<script setup>
import { dayjs, genFileId } from 'element-plus'
import { uploadOSS } from '@/api/home.js'
import { promotionImageList, insert, updateById } from '@/api/promotion.js'
import { ref } from 'vue';
// 显示添加表单
const type = ref(1) // 1添加 2编辑
const showDialog = ref(false)
const formLoading = ref(false)
// 获取添加小机构表单实例
let formRef = ref(null)
let uploadRef = ref(null)
const fileList = ref([])
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
}
// 创建表单
const form = reactive({
code: '',
name: '',
content: '',
type: '',
android: '',
ios: '',
id: ''
})
// 校验是否选择图片
const imgValidate = (rule, value, callback) => {
if (fileList.value.length <= 0) {
return callback(new Error('请选择图片'))
} else {
callback()
}
}
// 创建form校验规则
const rules = reactive({
code: [
{
required: true,
message: '',
trigger: 'blur'
}
],
name: [
{
required: true,
message: '',
trigger: 'blur'
}
],
content: [
{
required: true,
validator: imgValidate,
trigger: 'change'
}
],
type: [
{
required: true,
message: '请选择是否开启',
trigger: 'change'
}
],
android: [
{
required: true,
message: '请选择安卓是否开启',
trigger: 'change'
}
],
ios: [
{
required: true,
message: '请选择iOS是否开启',
trigger: 'change'
}
]
})
// 只能选择一个文件,替换之前的文件
const handleExceed = (files) => {
uploadRef.value.clearFiles()
const file = files[0]
file.uid = genFileId()
uploadRef.value.handleStart(file)
form.content = ''
}
// 选择图片
const selectFile = async (file) => {
// console.log('添加', file)
fileList.value = [file]
}
// 移除图片
const removeFile = async (file) => {
// console.log('移除', file.uid)
fileList.value = []
form.content = ''
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild) => {
if (vaild) {
try {
formLoading.value = true
if (type.value == 1) {
form.content = await uploadOSS(fileList.value[0].raw)
await insert(form)
ElMessage.success('添加成功')
} else {
if (!form.content) {
form.content = await uploadOSS(fileList.value[0].raw)
}
await updateById(form)
ElMessage.success('修改成功')
}
formLoading.value = false
showDialog.value = false
promotionImageListAjax()
} catch (error) {
formLoading.value = false
}
}
})
}
// ============================
// 表格参数
const tableOptions = reactive({
loading: true,
agencyCode: '',
list: [],
total: 0,
pageNum: 1,
pageSize: 10
})
// 分页回调
function paginationChange() {
tableOptions.loading = true
queryAgencyHandle()
}
// 添加推广图
const addHandle = () => {
type.value = 1
showDialog.value = true
}
// 编辑
const editorHandle = async (row) => {
showDialog.value = true
type.value = 2
form.content = row.content
form.id = JSON.stringify(row.id)
form.type = row.type
form.android = row.android
form.ios = row.ios
fileList.value = [{
name: `${row.content.slice(0, 19)}...`,
url: row.content
}]
}
// 推广宽图列表
const promotionImageListAjax = async () => {
try {
const { total, list } = await promotionImageList({
pageNum: tableOptions.pageNum,
pageSize: tableOptions.pageSize
})
tableOptions.loading = false
tableOptions.list = list
tableOptions.total = total
} catch (error) { }
}
onMounted(() => {
promotionImageListAjax()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 310px);
}
.mode_wrap {
display: flex;
flex-direction: column;
.height {
height: 4px;
}
}
</style>

View File

@@ -0,0 +1,291 @@
<template>
<div class="card">
<el-space>
<el-button type="primary" icon="Plus" @click="addHandle">添加菜单</el-button>
</el-space>
<div class="mt15">
<el-space>
<el-input placeholder="请输入appid搜索" v-model="tableOptions.appId" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
<el-button icon="RefreshRight" @click="resizeTable">重置</el-button>
</el-space>
</div>
<div class="table mt15">
<el-table ref="table" :data="tableOptions.list" border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column prop="appId" label="商户号"></el-table-column>
<el-table-column prop="merchantName" label="商户名称"></el-table-column>
<!-- <el-table-column prop="storeName" label="店铺名称"></el-table-column> -->
<el-table-column prop="ip" label="允许访问的ip"></el-table-column>
<el-table-column prop="publicKey" label="公钥">
<template #default="scope">
<el-popover title="点击复制" effect="dark" :width="500" :content="scope.row.publicKey">
<template #reference>
<el-text type="primary" tag="ins" truncated @click="copyHandle(scope.row.publicKey)">
<el-icon>
<CopyDocument />
</el-icon>
{{ scope.row.publicKey }}
</el-text>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="privateKey" label="私钥">
<template #default="scope">
<el-popover title="点击复制" effect="dark" :width="500" :content="scope.row.privateKey">
<template #reference>
<el-text type="primary" tag="ins" truncated @click="copyHandle(scope.row.privateKey)">
<el-icon>
<CopyDocument />
</el-icon>
{{ scope.row.privateKey }}
</el-text>
</template>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<template #default="scope">
<el-text>{{ scope.row.createTime && dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss')
}}</el-text>
</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间">
<template #default="scope">
<el-text>{{ scope.row.updateTime && dayjs(scope.row.updateTime).format('YYYY-MM-DD HH:mm:ss')
}}</el-text>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button type="primary" size="small" icon="Edit" @click="editorHandle(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSzie"
:page-size="tableOptions.pageSzie" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
<el-dialog title="新增api" v-model="showDialog" @closed="dialogClosed">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120" label-position="left">
<el-form-item prop="appId" label="appId" v-if="type == 1">
<el-input placeholder="请输入appId" v-model="form.appId" />
</el-form-item>
<el-form-item prop="ip" label="ip">
<el-input type="textarea" :autosize="{ minRows: 2 }" placeholder="请输入ip多个ip用,分割" v-model="form.ip" />
</el-form-item>
<el-form-item label="编辑公钥/私钥" v-if="type == 2">
<el-switch v-model="showKey"></el-switch>
</el-form-item>
<template v-if="showKey">
<el-form-item prop="publicKey" label="公钥">
<el-input type="textarea" :autosize="{ minRows: 2 }" placeholder="请输入公钥" v-model="form.publicKey" />
</el-form-item>
<el-form-item prop="privateKey" label="私钥">
<el-input type="textarea" :autosize="{ minRows: 2 }" placeholder="请输入私钥" v-model="form.privateKey" />
<el-text type="warning" size="small" v-if="type == 2">注意更改公钥/密钥会导致打印机无法使用</el-text>
</el-form-item>
<el-form-item>
<el-button type="success" icon="Connection" :loading="keyLoading"
@click="createKeyAjax">一键获取公钥/私钥</el-button>
</el-form-item>
</template>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" :loading="formLoading" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
</template>
<script setup>
import useClipboard from 'vue-clipboard3'
import { dayjs, ElMessage } from 'element-plus'
import { querySystemApis, createKey, initApi, modfityApi } from '@/api/setting.js'
const { toClipboard } = useClipboard()
const showKey = ref(true)
const table = ref(null)
// 表格参数
const tableOptions = reactive({
loading: true,
appId: '',
list: [],
total: 0,
pageNum: 1,
pageSzie: 10
})
// 显示添加表单
const showDialog = ref(false)
const formLoading = ref(false)
const type = ref(1) // 1添加 2编辑
const formRef = ref(null)
const keyLoading = ref(false)
// 创建表单
const form = reactive({
id: '',
appId: '',
ip: '',
publicKey: '',
privateKey: ''
})
// 表单校验规则
const rules = reactive({
appId: [
{
required: true,
message: '',
trigger: 'blur'
}
],
ip: [
{
required: true,
message: '',
trigger: 'blur'
}
],
publicKey: [
{
required: true,
message: '',
trigger: 'blur'
}
],
privateKey: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 编辑
function editorHandle(row) {
showDialog.value = true
showKey.value = false
type.value = 2
form.id = row.id
form.ip = row.ip
form.publicKey = row.publicKey
form.privateKey = row.privateKey
}
// 复制
async function copyHandle(text) {
try {
await toClipboard(text)
ElMessage.success('复制成功')
} catch (error) {
ElMessage.error('复制失败,请重试')
}
}
// 获取密钥对
async function createKeyAjax() {
try {
keyLoading.value = true
const res = await createKey()
ElMessage.success('获取成功')
keyLoading.value = false
form.publicKey = res.publicKey
form.privateKey = res.privateKey
} catch (error) {
keyLoading.value = false
}
}
// 表单关闭
function dialogClosed() {
formRef.value.resetFields()
form.id = ''
form.appId = ''
form.ip = ''
form.publicKey = ''
form.privateKey = ''
}
// 添加
function addHandle() {
type.value = 1
showDialog.value = true
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate(async (vaild) => {
if (vaild) {
try {
formLoading.value = true
if (type.value == 1) {
await initApi(form)
} else {
await modfityApi(form)
}
formLoading.value = false
showDialog.value = false
ElMessage.success(type.value == 1 ? '添加成功' : '编辑成功')
paginationChange()
} catch (error) {
formLoading.value = false
}
}
})
}
// 重置表格
function resizeTable() {
tableOptions.appId = ''
searchHandle()
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
getTableData()
}
// 获取appid 信息
async function getTableData() {
try {
const res = await querySystemApis({
appId: tableOptions.appId,
pageNum: tableOptions.pageNum,
pageSize: tableOptions.pageSzie
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
table.value.setScrollTop(0)
} catch (error) { }
}
onMounted(() => {
getTableData()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 356px);
}
</style>

View File

@@ -0,0 +1,218 @@
<template>
<div class="card">
<div>
<el-space>
<el-button type="primary" icon="Plus" @click="showDialogHandle">添加菜单</el-button>
</el-space>
</div>
<div class="mt15">
<el-table :data="tableData" style="width: 100%;">
<el-table-column prop="date" label="Date" width="180" />
<el-table-column prop="name" label="Name" width="180" />
<el-table-column prop="address" label="Address" />
</el-table>
</div>
<el-dialog v-model="showDialog" title="添加菜单" @closed="dialogClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100">
<el-form-item label="类型">
<el-radio-group v-model="form.is_menu">
<el-radio :label="1" border>菜单</el-radio>
<el-radio :label="0" border>按钮</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="name" :label="form.is_menu ? '菜单标识' : '按钮标识'">
<el-input :placeholder="form.is_menu ? '请输入菜单标识' : '请输入按钮标识'" clearable v-model="form.name" />
</el-form-item>
<el-form-item prop="title" :label="form.is_menu ? '菜单标题' : '按钮标题'">
<el-input :placeholder="form.is_menu ? '请输入菜单标题' : '请输入按钮标题'" clearable v-model="form.title" />
</el-form-item>
<template v-if="form.is_menu">
<el-form-item prop="path" label="菜单地址">
<el-input placeholder="请输入菜单地址" clearable v-model="form.path" />
</el-form-item>
<el-form-item prop="component" label="组件地址">
<el-input placeholder="请输入组件地址" clearable v-model="form.component" />
</el-form-item>
<el-form-item label="菜单重定向">
<el-input placeholder="请输入重定向地址" clearable v-model="form.redirect" />
</el-form-item>
<el-form-item prop="icon" label="菜单图标">
<el-input placeholder="请选择菜单图标" clearable v-model="form.icon" suffix-icon="ArrowRight" readonly
style="width: 150px;" @click="showIconDialog = true" />
<el-button :icon="form.icon" v-show="form.icon" style="margin-left: 10px;"></el-button>
</el-form-item>
<el-form-item label="是否隐藏">
<el-radio-group v-model="form.isHide">
<el-radio :label="false" border>显示</el-radio>
<el-radio :label="true" border>隐藏</el-radio>
</el-radio-group>
</el-form-item>
</template>
</el-form>
<template #footer>
<el-space>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="submitHandle">提交</el-button>
</el-space>
</template>
</el-dialog>
<el-dialog v-model="showIconDialog" title="选择图标" @opened="iconLoading = false">
<div class="icon_list">
<div class="item" v-for="item in ElIcons" :key="item" @click="selectIocnHandle(item.name)">
<SvgIcon :name="item.name" size="30"></SvgIcon>
<span class="name">{{ item.name }}</span>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import * as ElIcons from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
// 获取表单ref
let formRef = ref(null);
// 控制选择图片显示
let showIconDialog = ref(false)
const tableData = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
}
]
const formType = ref(1);
const form = reactive({
id: '',
pid: 0,
is_menu: 1,
path: '',
name: '',
component: '',
redirect: '',
title: '',
icon: '',
isHide: false
})
const rules = reactive({
path: [
{
required: true,
message: '',
trigger: 'blur'
}
],
name: [
{
required: true,
message: '',
trigger: 'blur'
}
],
title: [
{
required: true,
message: '',
trigger: 'blur'
}
],
component: [
{
required: true,
message: '',
trigger: 'blur'
}
],
btn_name: [
{
required: true,
message: '',
trigger: 'blur'
}
],
btn_title: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
const showDialog = ref(false)
// 关闭dialog
const dialogClose = () => {
formRef.value.resetFields()
}
// 显示dialog
const showDialogHandle = () => {
showDialog.value = true
formType.value = 1
}
// 提交表单
const submitHandle = async () => {
await formRef.value.validate((vaild, fields) => {
if (vaild) {
console.log('通过')
}
})
}
// 选择icon
const selectIocnHandle = (name) => {
console.log(name)
form.icon = name
showIconDialog.value = false
}
onMounted(() => {
})
</script>
<style scoped lang="scss">
.icon_list {
height: 50vh;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
.item {
flex: 0 0 25%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 60px;
&:hover {
cursor: pointer;
background-color: #efefef;
}
.name {
font-size: 12px;
}
}
}
</style>

View File

@@ -0,0 +1,20 @@
<template>
<el-card shadow="hover" header="wangeditor 富文本编辑器">
<Editor v-model:get-html="state.editor.htmlVal" v-model:get-text="state.editor.textVal" :disable="state.editor.disable" />
</el-card>
</template>
<script setup>
import Editor from "@/components/editor.vue";
// 定义变量内容
const state = reactive({
editor: {
htmlVal: "<h1>wangeditor 富文本编辑器</h1>",
textVal: "wangeditor 富文本编辑器",
disable: false,
},
});
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,440 @@
<template>
<div class="card">
<div class="data_row">
<div class="item">
<div class="icon">
<img class="img" src="@/assets/icon_earnings2.png">
</div>
<div class="info">
<div class="title">总收益</div>
<div class="num">
<count-to :start-val="0" :end-val="earnings.sumProfit" :duration="1000" :decimals="2" prefix="¥" />
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="@/assets/icon_earnings1.png">
</div>
<div class="info">
<div class="title">可提现收益</div>
<div class="num">
<count-to :start-val="0" :end-val="earnings.availableBalance" :duration="1000" :decimals="2"
prefix="¥" />
</div>
<div class="btn_wrap">
<div class="btn">
<el-button type="primary" size="small" icon="CreditCard"
@click="showWithdraw = true">申请提现</el-button>
</div>
<div class="btn">
<el-button type="warning" size="small" icon="Document"
@click="getUserOutFlowHandleResize">提现记录</el-button>
</div>
</div>
</div>
</div>
<div class="item">
<div class="icon">
<img class="img" src="@/assets/icon_earnings3.png">
</div>
<div class="info">
<div class="title">提现中收益</div>
<div class="num">
<count-to :start-val="0" :end-val="earnings.fronZenAmt" :duration="1000" :decimals="2" prefix="¥" />
</div>
</div>
</div>
</div>
</div>
<div class="card mt15">
<el-space>
<el-input placeholder="请输入订单号搜索" v-model="tableOptions.orderNumber" style="width: 200px;" />
<el-input placeholder="请输入商户号搜索" v-model="tableOptions.merchantCode" style="width: 200px;" />
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="mt15">
<div class="table">
<el-table :data="tableOptions.list" size="large" stripe border height="100%"
v-loading="tableOptions.loading">
<el-table-column prop="price" label="收益"></el-table-column>
<el-table-column prop="consumeFee" label="收款金额"></el-table-column>
<!-- <el-table-column prop="loginName" label="名称"></el-table-column> -->
<el-table-column prop="merchantName" label="商家名称"></el-table-column>
<el-table-column prop="merchantName" label="收益来源">
<template #default="scope">
<el-text>{{ scope.row.loginName }}</el-text>
<el-tag disable-transitions style="margin-left: 8px;">{{ typeNames[scope.row.typeCode]
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="createDt" label="时间">
<template #default="scope">
{{ dayjs(scope.row.createDt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSize"
:page-size="tableOptions.pageSize" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
</div>
<el-dialog v-model="showWithdraw" title="申请提现" width="600" @closed="formRef.resetFields()">
<el-space>
<el-form ref="formRef" :model="form" :rules="rules">
<el-form-item label="提现金额" prop="num">
<el-space>
<el-input placeholder="请输入提现金额" clearable style="width: 300px;" :model-value="form.num"
@input="numInput" />
<el-button type="primary" @click="form.num = ((earnings.availableBalance / 100) * 100).toFixed(2)">
全部提现({{ ((earnings.availableBalance / 100) * 100).toFixed(2) }})
</el-button>
</el-space>
</el-form-item>
</el-form>
</el-space>
<template #footer>
<span class="dialog-footer">
<el-button @click="showWithdraw = false">取消</el-button>
<el-button type="primary" :loading="form.loading" @click="submitHandle">确定</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="records.show" title="提现记录">
<el-row>
<el-select v-model="records.status" @change="recordsPaginationChange">
<el-option label="全部" value="" key="" />
<el-option label="待审核" :value="0" :key="0" />
<el-option label="审核通过" :value="1" :key="1" />
<el-option label="提现失败" :value="2" :key="2" />
<el-option label="审核中" :value="3" :key="3" />
</el-select>
</el-row>
<div class="records_table mt15">
<el-table :data="records.list" size="large" border height="100%" v-loading="records.loading">
<el-table-column prop="id" label="机构id"></el-table-column>
<el-table-column prop="cashAmt" label="提现金额">
<template #default="scope">
<el-text type="primary">{{ scope.row.cashamt }}</el-text>
</template>
</el-table-column>
<el-table-column prop="createDt" label="提现时间" width="250">
<template #default="scope">
<el-text>{{ dayjs(scope.row.createdt).format('YYYY-MM-DD HH:mm:ss') }}</el-text>
</template>
</el-table-column>
<el-table-column label="状态">
<template #default="scope">
<el-tag type="info" disable-transitions v-if="scope.row.status == 0">待审核</el-tag>
<el-tag type="success" disable-transitions v-if="scope.row.status == 1">提现成功</el-tag>
<el-tag type="warning" disable-transitions v-if="scope.row.status == 2">提现失败</el-tag>
<el-tag type="info" disable-transitions v-if="scope.row.status == 3">审核中</el-tag>
</template>
</el-table-column>
<el-table-column prop="cashStatus" label="上级审核信息">
<template #default="scope">
<el-link type="primary" icon="Search"
@click="showCheckModle(scope.$index, scope.row.cashstatus)">查看进度</el-link>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="records.pageNum" v-model:page-size="records.pageSize" :page-size="records.pageSize"
:page-sizes="[10, 20, 30, 50]" :total="records.total" @size-change="recordsPaginationChange"
@current-change="recordsPaginationChange" />
</div>
<el-dialog v-model="records.showProgress" title="审核进度">
<el-steps :active="rowProgressActive" align-center>
<el-step :title="typeNames[item.userType]" :description="statusEmun[item.status]"
v-for="(item, index) in rowProgress" :key="index"></el-step>
</el-steps>
<div style="padding-bottom: 28px;"></div>
</el-dialog>
</el-dialog>
</template>
<script setup>
import hooks from '@/hooks'
import { dayjs } from 'element-plus';
import { typeNames, clearNoNum } from '@/utils/index.js'
import { queryProfit, getUserBalance, withdrawalProfit, getUserOutFlow } from '@/api/organization.js'
import { onMounted, reactive, ref } from 'vue';
import { ElMessage } from 'element-plus'
// 表格参数
const tableOptions = reactive({
loading: true,
reqUserId: '', // 上级id
orderNumber: '', // 订单号
merchantCode: '', // 商户号
list: [],
total: 0,
pageNum: 1,
pageSize: 10
})
// 收益数据
const earnings = reactive({
sumProfit: 0,
availableBalance: 0,
fronZenAmt: 0
})
// 显示提现弹窗
const formRef = ref()
const showWithdraw = ref(false)
const form = reactive({
num: '',
loading: false
})
const rules = reactive({
num: [
{
required: true,
message: '',
trigger: 'blur'
}
]
})
// 格式化数字
function numInput(e) {
let n = clearNoNum({ value: e })
if (n <= earnings.availableBalance) {
form.num = n
} else {
form.num = ((earnings.availableBalance / 100) * 100).toFixed(2)
}
}
// 提交提现申请
async function submitHandle() {
await formRef.value.validate(async (valid) => {
if (valid) {
try {
form.loading = true
await withdrawalProfit({
amount: form.num
})
form.loading = false
showWithdraw.value = false
getUserBalanceHandle()
} catch (error) {
form.loading = false
}
}
})
}
// 提现记录
const records = reactive({
show: false,
showProgress: false,
loading: false,
status: '',
list: [],
total: 0,
pageNum: 1,
pageSize: 10
})
// 当前表格索引
const rowIndex = ref(0)
// 当前进度数组
const rowProgress = ref([])
// 当前进度索引
const rowProgressActive = ref(0)
// 状态枚举
const statusEmun = ref({
"0": '待审核',
"1": '审核通过',
"2": '提现失败',
"3": '审核中'
})
// 查看当前进度
function showCheckModle(row, cashStatus) {
if (cashStatus) {
records.showProgress = true
rowIndex.value = row
console.log(JSON.parse(cashStatus))
rowProgress.value = JSON.parse(cashStatus)
rowProgress.value.map((item, index) => {
if (item.status != 0) {
rowProgressActive.value = index + 1
}
})
} else {
ElMessage.error('暂时无法查看,请稍后再试!')
}
}
// 提现记录分页回调
function recordsPaginationChange() {
getUserOutFlowHandle()
}
// 重新获取提现记录
function getUserOutFlowHandleResize() {
records.show = true
records.pageNum = 1
records.loading = true
getUserOutFlowHandle()
}
// 获取提现流水
async function getUserOutFlowHandle() {
try {
const { total, list } = await getUserOutFlow({
status: records.status,
pageNum: records.pageNum,
pageSize: records.pageSize
})
records.loading = false
records.list = list
records.total = total
} catch (error) {
records.loading = false
}
}
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
paginationChange()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
getTableDate()
}
// 获取机构列表
async function getTableDate() {
try {
const res = await queryProfit({
reqUserId: hooks.useLocalStorage.get('userInfo').userId,
orderNumber: tableOptions.orderNumber,
merchantCode: tableOptions.merchantCode,
pageNum: tableOptions.pageNum,
pageSize: tableOptions.pageSize
})
tableOptions.loading = false
tableOptions.list = res.list
tableOptions.total = res.total
} catch (error) { }
}
// 查询用户总收益和可提收益,冻结收益 ,已提收益
async function getUserBalanceHandle() {
try {
const res = await getUserBalance()
earnings.sumProfit = res.sumProfit
earnings.availableBalance = res.availableBalance
earnings.fronZenAmt = res.fronZenAmt
} catch (error) { }
}
onMounted(() => {
getTableDate()
getUserBalanceHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 455px);
}
.records_table {
height: 50vh;
}
.data_row {
display: flex;
padding: 24px 0;
.item {
flex: 1;
display: flex;
padding-left: 50px;
&:not(:last-child) {
position: relative;
&::after {
content: "";
height: 100%;
border-right: 1px solid #ececec;
position: absolute;
top: 0;
right: 0;
}
}
.icon {
$size: 50px;
width: $size;
height: $size;
.img {
width: $size;
height: $size;
}
}
.info {
flex: 1;
padding-left: 20px;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
.title {
font-size: 14px;
color: #666;
font-weight: 300;
}
.num {
font-size: 24px;
font-weight: bold;
padding-top: 10px;
.i {
font-size: 12px;
position: relative;
bottom: 1px;
right: -4px;
}
}
.btn_wrap {
position: absolute;
top: 0;
right: 14%;
display: flex;
flex-direction: column;
.btn {
flex: 1;
&:last-child {
margin-top: 4px;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,202 @@
<template>
<div class="card">
<el-space>
<el-input placeholder="用户名称" v-model="tableOptions.userName" style="width: 200px;" />
<el-input placeholder="商户号" v-model="tableOptions.merchantCode" style="width: 200px;" />
<el-select v-model="tableOptions.status">
<el-option key="" value="" label="全部"></el-option>
<el-option :key="0" :value="0" label="待审核"></el-option>
<el-option :key="1" :value="1" label="提现成功"></el-option>
<el-option :key="2" :value="2" label="提现失败"></el-option>
<el-option :key="3" :value="3" label="审核中"></el-option>
</el-select>
<el-button type="primary" icon="Search" @click="searchHandle">搜索</el-button>
</el-space>
<div class="table mt15">
<el-table :data="tableOptions.list" size="large" stripe border height="100%" v-loading="tableOptions.loading">
<el-table-column prop="id" label="机构id"></el-table-column>
<el-table-column prop="merchantCode" label="商户号"></el-table-column>
<el-table-column prop="userName" label="商户名称"></el-table-column>
<el-table-column prop="accountNo" label="账户号"></el-table-column>
<el-table-column prop="cashAmt" label="提现金额">
<template #default="scope">
<el-text type="primary">{{ scope.row.cashAmt }}</el-text>
</template>
</el-table-column>
<el-table-column prop="userId" label="用户id"></el-table-column>
<el-table-column prop="createDt" label="提现时间">
<template #default="scope">
<el-text>{{ dayjs(scope.row.createDt).format('YYYY-MM-DD HH:mm:ss') }}</el-text>
</template>
</el-table-column>
<el-table-column prop="typeCode" label="提现人身份">
<template #default="scope">
<el-tag disable-transitions>{{ typeNames[scope.row.typeCode] }}</el-tag>
</template>
</el-table-column>
<el-table-column label="状态">
<template #default="scope">
<el-tag type="info" v-if="scope.row.status == 0">待审核</el-tag>
<el-tag type="success" v-if="scope.row.status == 1">提现成功</el-tag>
<el-tag type="warning" v-if="scope.row.status == 2">提现失败</el-tag>
<el-tag type="info" v-if="scope.row.status == 3">审核中</el-tag>
</template>
</el-table-column>
<el-table-column prop="cashStatus" label="上级审核信息">
<template #default="scope">
<el-link type="primary" icon="Search"
@click="showCheckModle(scope.$index, scope.row.cashStatus)">查看进度</el-link>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<template v-if="scope.row.show && scope.row.status != 2">
<el-popconfirm title="是否审核通过?" width="200" confirm-button-text="通过" cancel-button-text="驳回"
@cancel="checkHandle(scope.row, 2)" @confirm="checkHandle(scope.row, 1)">
<template #reference>
<el-button type="primary" size="small" icon="EditPen">审核</el-button>
</template>
</el-popconfirm>
</template>
<template v-else>
<el-button type="default" size="small" icon="EditPen" disabled>
审核
</el-button>
</template>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt15">
<el-pagination layout="prev, pager, next, total, sizes, jumper" background
v-model:current-page="tableOptions.pageNum" v-model:page-size="tableOptions.pageSize"
:page-size="tableOptions.pageSize" :page-sizes="[10, 20, 30, 50]" :total="tableOptions.total"
@size-change="paginationChange" @current-change="paginationChange" />
</div>
<el-dialog v-model="show" title="审核进度">
<el-steps :active="rowProgressActive" align-center>
<el-step :title="typeNames[item.userType]" :description="statusEmun[item.status]"
v-for="(item, index) in rowProgress" :key="index"></el-step>
</el-steps>
<div style="padding-bottom: 28px;"></div>
</el-dialog>
</div>
</template>
<script setup>
import { getOutFlow, modifyOutFlow } from '@/api/withdraw.js'
import { onMounted, reactive, ref } from 'vue'
import { typeNames } from '@/utils/index.js'
import { ElMessage } from 'element-plus'
import { dayjs } from 'element-plus'
import hooks from '@/hooks'
// 显示进度dialog
const show = ref(false)
// 当前表格索引
const rowIndex = ref(0)
// 当前进度数组
const rowProgress = ref([])
// 当前进度索引
const rowProgressActive = ref(0)
// 状态枚举
const statusEmun = ref({
"0": '待审核',
"1": '审核通过',
"2": '提现失败',
"3": '审核中'
})
// 查看当前进度
function showCheckModle(row, cashStatus) {
show.value = true
rowIndex.value = row
console.log(JSON.parse(cashStatus))
rowProgress.value = JSON.parse(cashStatus)
rowProgress.value.map((item, index) => {
if (item.status != 0) {
rowProgressActive.value = index + 1
}
})
}
// 审核操作
async function checkHandle(row, status) {
try {
await modifyOutFlow({
id: row.id,
status: status
})
ElMessage.success('提交成功')
paginationChange()
} catch (error) { }
}
// 表格参数
const tableOptions = reactive({
loading: true,
userName: '',
merchantCode: '',
status: 0,
list: [],
total: 0,
pageNum: 1,
pageSize: 10
})
// 搜索
function searchHandle() {
tableOptions.pageNum = 1;
getOutFlowHandle()
}
// 分页回调
function paginationChange() {
tableOptions.loading = true
getOutFlowHandle()
}
// 提现申请查询
async function getOutFlowHandle() {
try {
const res = await getOutFlow({
userName: tableOptions.userName,
merchantCode: tableOptions.merchantCode,
status: tableOptions.status,
pageNum: tableOptions.pageNum,
pageSize: tableOptions.pageSize
})
const userInfo = hooks.useLocalStorage.get('userInfo')
const data = [...res.list];
// console.log(userInfo.userType)
for (let item of data) {
item.show = false;
const arr = JSON.parse(item.cashStatus);
// console.log(arr);
for (let child of arr) {
if (child.userType == userInfo.userType && child.status == 0) {
item.show = true;
}
}
}
tableOptions.loading = false
tableOptions.list = data
tableOptions.total = res.total
} catch (error) { }
}
onMounted(() => {
getOutFlowHandle()
})
</script>
<style scoped lang="scss">
.table {
height: calc(100vh - 310px);
}
</style>