商户管理

This commit is contained in:
DESKTOP-GMUNQ1B\k 2024-04-24 09:56:53 +08:00
parent 470b4f540d
commit 5622b0d02d
22 changed files with 2823 additions and 558 deletions

12
package-lock.json generated
View File

@ -18,6 +18,7 @@
"echarts": "^5.3.3",
"element-plus": "2.2.27",
"highlight.js": "^11.6.0",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^2.0.14",
"vue": "^3.2.37",
@ -5655,6 +5656,12 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"license": "MIT"
},
"node_modules/mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz",
@ -13509,6 +13516,11 @@
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
"dev": true
},
"mitt": {
"version": "3.0.1",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
},
"mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz",

View File

@ -19,6 +19,7 @@
"echarts": "^5.3.3",
"element-plus": "2.2.27",
"highlight.js": "^11.6.0",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^2.0.14",
"vue": "^3.2.37",

View File

@ -1,46 +1,46 @@
<script setup lang="ts">
import { useDark, useWindowSize, useThrottleFn } from '@vueuse/core'
import { useDark, useWindowSize, useThrottleFn } from "@vueuse/core";
import zhCn from "element-plus/es/locale/lang/zh-cn";
import useAppStore from './stores/modules/app'
import useSettingStore from './stores/modules/setting'
import { ScreenEnum } from './enums/appEnums'
const appStore = useAppStore()
const settingStore = useSettingStore()
import useAppStore from "./stores/modules/app";
import useSettingStore from "./stores/modules/setting";
import { ScreenEnum } from "./enums/appEnums";
const appStore = useAppStore();
const settingStore = useSettingStore();
const elConfig = {
zIndex: 3000,
locale: zhCn
}
const isDark = useDark()
zIndex: 3000,
locale: zhCn,
};
const isDark = useDark();
onMounted(async () => {
//
settingStore.setTheme(isDark.value)
})
//
settingStore.setTheme(isDark.value);
});
const { width } = useWindowSize()
const { width } = useWindowSize();
watch(
width,
useThrottleFn((value) => {
if (value > ScreenEnum.SM) {
appStore.setMobile(false)
appStore.toggleCollapsed(false)
} else {
appStore.setMobile(true)
appStore.toggleCollapsed(true)
}
if (value < ScreenEnum.MD) {
appStore.toggleCollapsed(true)
}
}),
{
immediate: true
width,
useThrottleFn((value) => {
if (value > ScreenEnum.SM) {
appStore.setMobile(false);
appStore.toggleCollapsed(false);
} else {
appStore.setMobile(true);
appStore.toggleCollapsed(true);
}
)
if (value < ScreenEnum.MD) {
appStore.toggleCollapsed(true);
}
}),
{
immediate: true,
}
);
</script>
<template>
<el-config-provider :locale="elConfig.locale" :z-index="elConfig.zIndex">
<router-view />
</el-config-provider>
<el-config-provider :locale="elConfig.locale" :z-index="elConfig.zIndex">
<router-view />
</el-config-provider>
</template>
<style></style>

21
src/api/cate_time.ts Normal file
View File

@ -0,0 +1,21 @@
import request from '@/utils/request';
// 分类定时列表
export function cateTimeListsApi(params: any) {
return request.get({ url: '/cate.cate_time/lists', params })
}
// 分类定时添加
export function cateTimeAddApi(params: any) {
return request.post({ url: '/cate.cate_time/add', params })
}
// 分类定时修改
export function cateTimeEditApi(params: any) {
return request.post({ url: '/cate.cate_time/edit', params })
}
// 分类定时删除
export function cateTimeDelApi(params: any) {
return request.post({ url: '/cate.cate_time/delete', params })
}

View File

@ -5,6 +5,11 @@ export function merchantList(params: any) {
return request.get({ url: '/merchant.merchant/lists', params })
}
// 商户列表----无分页
export function merchantListNoPage(params: any) {
return request.get({ url: '/merchant.merchant/merchantList', params })
}
// 修改商户相关信息
export function merchantUpdate(params: any) {
return request.post({ url: '/merchant.merchant/changeMerchant', params })
@ -15,12 +20,16 @@ export function merchantDetail(params: any) {
return request.post({ url: '/merchant.merchant/detail', params })
}
// 获取记录人 子管理员
export function childManagement(params: any) {
return request.get({ url: '/record.record/info', params })
}
// 获取记录人 子管理员
export function recordManApi(params: any) {
return request.get({ url: '/merchant.merchant/recordMan', params })
}
// 商户管理员绑定
export function merchantBind(params: any) {
return request.post({ url: '/merchant.merchant/merchantPermision', params })
@ -36,3 +45,39 @@ export function storeSuper(params: any) {
return request.post({ url: '/merchant.merchant/storeSuper', params })
}
// 保存督导
export function saveConditionApi(params: any) {
return request.get({ url: '/store.store_condition/saveCondition', params })
}
// 消息列表
export function newList(params: any) {
return request.get({ url: '/new.new/lists', params })
}
// excel 导出
export function excelListApi(params: any) {
return request.get({ url: '/merchant.merchant/excelList', params })
}
// excel 预下载
export function excelApi(params: any) {
return request.get({ url: '/merchant.merchant/excel', params })
}
// 商户分类
export function merchantCategoryApi(params: any) {
return request.get({ url: '/merchant.merchant/merchantCategory', params })
}
// 区域分类
export function merchantAreaListApi(params: any) {
return request.get({ url: '/merchant.merchant/AreatList', params })
}
// 镇街道
export function streetListApi(params: any) {
return request.get({ url: '/merchant.merchant/streetList', params })
}

31
src/api/monitor.ts Normal file
View File

@ -0,0 +1,31 @@
import request from '@/utils/request';
// 督导列表
export function monitorListApi(params: any) {
return request.get({ url: '/store.store_condition/lists', params })
}
// 督导添加
export function monitorAddApi(params: any) {
return request.post({ url: '/store.store_condition/add', params })
}
// 督导修改
export function monitorEditApi(params: any) {
return request.post({ url: '/store.store_condition/edit', params })
}
// 督导删除
export function monitorDelApi(params: any) {
return request.post({ url: '/store.store_condition/delete', params })
}
// 督导详情by id
export function monitorDetailApi(params: any) {
return request.get({ url: '/store.store_condition/detail', params })
}
// 督导详情by mer_id
export function monitorByMerIdApi(params: any) {
return request.get({ url: '/store.store_condition/merchantDetail', params })
}

View File

@ -0,0 +1,26 @@
import request from '@/utils/request'
// 店铺督促表列表
export function apiStoreConditionLists(params: any) {
return request.get({ url: '/store.store_condition/lists', params })
}
// 添加店铺督促表
export function apiStoreConditionAdd(params: any) {
return request.post({ url: '/store.store_condition/add', params })
}
// 编辑店铺督促表
export function apiStoreConditionEdit(params: any) {
return request.post({ url: '/store.store_condition/edit', params })
}
// 删除店铺督促表
export function apiStoreConditionDelete(params: any) {
return request.post({ url: '/store.store_condition/delete', params })
}
// 店铺督促表详情
export function apiStoreConditionDetail(params: any) {
return request.get({ url: '/store.store_condition/detail', params })
}

View File

@ -0,0 +1,64 @@
<template>
<div style="display: flex">
<el-icon :size="18" @click="onOpen"><Download /></el-icon>
<el-drawer v-model="drawShow" title="Excel下载" :direction="'rtl'" size="35%">
<el-table :data="excelData" stripe>
<el-table-column type="selection" width="55" />
<el-table-column
label="名称"
prop="record"
min-width="120"
show-overflow-tooltip
/>
<el-table-column label="状态" prop="status" min-width="80">
<template #default="{ row }">
<el-tag type="primary" v-if="row.status == 0">生成中</el-tag>
<el-tag type="success" v-if="row.status == 1">成功</el-tag>
<el-tag type="danger" v-if="row.status == 2">失败</el-tag>
</template>
</el-table-column>
<el-table-column
label="下载地址"
prop="excel_path"
min-width="200"
show-overflow-tooltip
>
<template #default="{ row }">
<span type="success" v-if="row.status == 1">{{ row.excel_path }}</span>
<span type="danger" v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ row }">
<el-link :href="row.excel_path" target="_blank">下载</el-link>
</template>
</el-table-column>
</el-table>
</el-drawer>
</div>
</template>
<script setup lang="ts">
//
import { useRouter } from "vue-router";
import { excelListApi } from "@/api/merchant";
import { getRoutePath } from "@/router";
const drawShow = ref(false);
//
const onOpen = () => {
drawShow.value = true;
getExcelData();
};
//
const excelData = ref([]);
const getExcelData = () => {
excelListApi("").then((res) => {
excelData.value = res;
console.log(excelData);
});
};
</script>

View File

@ -1,55 +1,65 @@
<template>
<header class="header">
<div class="navbar">
<div class="flex-1 flex">
<div class="navbar-item">
<fold />
</div>
<div class="navbar-item">
<refresh />
</div>
<div class="flex items-center px-2" v-if="!isMobile && settingStore.showCrumb">
<breadcrumb />
</div>
</div>
<div class="flex">
<div class="navbar-item" v-if="!isMobile">
<full-screen />
</div>
<div class="navbar-item">
<user-drop-down />
</div>
<div class="navbar-item">
<setting />
</div>
</div>
<header class="header">
<div class="navbar">
<div class="flex-1 flex">
<div class="navbar-item">
<fold />
</div>
<multiple-tabs v-if="settingStore.openMultipleTabs" />
</header>
<div class="navbar-item">
<refresh />
</div>
<div class="flex items-center px-2" v-if="!isMobile && settingStore.showCrumb">
<breadcrumb />
</div>
</div>
<div class="flex">
<div class="navbar-item">
<download />
</div>
<div class="navbar-item" style="margin-left: 10px">
<notice />
</div>
<div class="navbar-item" v-if="!isMobile" style="margin-left: 10px">
<full-screen />
</div>
<div class="navbar-item">
<user-drop-down />
</div>
<div class="navbar-item">
<setting />
</div>
</div>
</div>
<multiple-tabs v-if="settingStore.openMultipleTabs" />
</header>
</template>
<script setup lang="ts">
import useAppStore from '@/stores/modules/app'
import Fold from './fold.vue'
import Refresh from './refresh.vue'
import Breadcrumb from './breadcrumb.vue'
import FullScreen from './full-screen.vue'
import UserDropDown from './user-drop-down.vue'
import Setting from '../setting/index.vue'
import MultipleTabs from './multiple-tabs.vue'
import useAppStore from "@/stores/modules/app";
import Fold from "./fold.vue";
import Refresh from "./refresh.vue";
import Breadcrumb from "./breadcrumb.vue";
import FullScreen from "./full-screen.vue";
import notice from "./notice.vue";
import download from "./download.vue";
import UserDropDown from "./user-drop-down.vue";
import Setting from "../setting/index.vue";
import MultipleTabs from "./multiple-tabs.vue";
import useSettingStore from '@/stores/modules/setting'
const appStore = useAppStore()
const isMobile = computed(() => appStore.isMobile)
const settingStore = useSettingStore()
import useSettingStore from "@/stores/modules/setting";
const appStore = useAppStore();
const isMobile = computed(() => appStore.isMobile);
const settingStore = useSettingStore();
</script>
<style lang="scss">
.navbar {
height: var(--navbar-height);
@apply flex px-2 bg-body;
.navbar-item {
@apply h-full flex justify-center items-center hover:bg-page;
}
height: var(--navbar-height);
@apply flex px-2 bg-body;
.navbar-item {
@apply h-full flex justify-center items-center hover:bg-page;
}
}
</style>

View File

@ -0,0 +1,58 @@
<template>
<div>
<el-popover placement="bottom" trigger="hover" width="200px">
<template #reference>
<el-badge
:is-dot="newsList.length > 0 ? true : false"
class="item"
style="display: flex; align-items: center; height: 100%; cursor: pointer"
>
<el-icon :size="16"><Bell /></el-icon>
</el-badge>
</template>
<el-table
:data="newsList"
@row-click="rowClick"
max-height="300"
:show-header="false"
>
<el-table-column
width="160"
property="type_name"
label="店铺类型"
align="center"
/>
</el-table>
</el-popover>
</div>
</template>
<script setup lang="ts">
//
import { useRouter } from "vue-router";
import { newList } from "@/api/merchant";
import { getRoutePath } from "@/router";
import { ref, getCurrentInstance, type ComponentInternalInstance, onMounted, onBeforeMount } from "vue";
const { appContext } = getCurrentInstance() as ComponentInternalInstance;
const newsList = ref([]);
onMounted(()=>{
appContext.config.globalProperties.$mitt.on('selfEvent',(res:any)=>{
console.log('执行了自定义方法')
//
newList("").then((res) => {
newsList.value = res;
});
})
})
//
const router = useRouter();
const rowClick = (row: any) => {
router.push({
path: getRoutePath("merchant.merchant/lists"),
query: { mer_ids: row.mer_ids.join(",") },
});
};
</script>

View File

@ -4,7 +4,11 @@ import install from './install'
import './permission'
import './styles/index.scss'
import 'virtual:svg-icons-register'
import mitt from 'mitt';
const app = createApp(App)
app.config.globalProperties.$mitt = mitt();
app.use(install)
app.mount('#app')

View File

@ -0,0 +1,151 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="550px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="90px" :rules="formRules">
<el-form-item label="店铺类型" prop="type_id">
<el-select
class="w-[280px]"
placeholder="请输入店铺类型"
v-model="formData.type_id"
>
<el-option
v-for="item in merchantData"
:label="item.type_name"
:value="item.mer_type_id"
:key="item.mer_type_id"
/>
</el-select>
</el-form-item>
<el-form-item label="店铺类型" prop="open">
<el-switch v-model="formData.open" active-text="开启" inactive-text="关闭">
</el-switch>
</el-form-item>
<el-form-item label="日期" prop="time">
<el-date-picker v-model="formData.time" type="date" placeholder="选择天数">
</el-date-picker>
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup name="cateTimeEdit">
import type { FormInstance } from "element-plus";
import Popup from "@/components/popup/index.vue";
import { merchantCate } from "@/api/merchant";
import { apiRecordDetail } from "@/api/record";
import { cateTimeAddApi, cateTimeEditApi } from "@/api/cate_time";
const emit = defineEmits(["success", "close"]);
const formRef = shallowRef<FormInstance>();
const popupRef = shallowRef<InstanceType<typeof Popup>>();
const mode = ref("add");
//
const popupTitle = computed(() => {
return mode.value == "edit" ? "编辑分类定时" : "新增分类定时";
});
//
const formData = reactive({
id: "",
type_id: "",
time: "",
open: true,
});
//
const merchantData: any = ref([]);
const getMerchantCate = async () => {
merchantData.value = await merchantCate("");
};
//
const formRules = reactive<any>({
type_id: [
{
required: true,
message: "请选择店铺类型",
trigger: ["change"],
},
],
time: [
{
required: true,
message: "请选择执行时间",
trigger: ["change"],
},
],
open: [
{
required: true,
message: "请选择状态",
trigger: ["change"],
},
],
});
//
const setFormData = async (data: Record<any, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
if (key == "open") {
formData[key] = data[key] == 1 ? true : false;
} else if (key == "time") {
let year = new Date().getFullYear();
let month = new Date().getMonth() + 1;
formData[key] = `${year}-${month}-${data[key]}`;
} else {
formData[key] = data[key];
}
}
}
};
//
const handleSubmit = async () => {
await formRef.value?.validate();
const data = { ...formData };
data.time = new Date(data.time).getDate();
mode.value == "edit" ? await cateTimeEditApi(data) : await cateTimeAddApi(data);
popupRef.value?.close();
emit("success");
};
//
const open = (type = "add", merId = "") => {
mode.value = type;
popupRef.value?.open();
if (merId) {
formData.merchant_id = merId;
}
};
//
const handleClose = () => {
emit("close");
};
getMerchantCate();
defineExpose({
open,
setFormData,
});
</script>
<style lang="scss">
.el-input__wrapper {
width: 100%;
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<div>
<el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="店铺类型" prop="type_id">
<el-select
placeholder="请选择商户"
v-model="queryParams.type_id"
class="w-[280px]"
filterable
>
<el-option
v-for="(item, indx) in merchantData"
:key="item.mer_type_id"
:value="item.mer_type_id + ''"
:label="item.type_name"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<el-button v-perms="['record.record/add']" type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<div class="mt-4">
<el-table :data="pager.lists">
<el-table-column type="selection" width="55" />
<el-table-column
label="店铺类型"
prop="cate_name"
min-width="200"
show-overflow-tooltip
/>
<el-table-column label="执行时间" prop="time" show-overflow-tooltip />
<el-table-column label="状态" prop="open" show-overflow-tooltip>
<template #default="{ row }">
<el-tag v-if="row.open == 1" type="success">开启</el-tag>
<el-tag v-else type="danger">关闭</el-tag>
</template>
</el-table-column>
<el-table-column
label="创建时间"
prop="create_time"
min-width="160"
show-overflow-tooltip
/>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
<el-button type="danger" link @click="handleDelete(row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup
v-if="showEdit"
ref="editRef"
@success="getLists"
@close="showEdit = false"
/>
</div>
</template>
<script lang="ts" setup name="cateTimeList">
import { usePaging } from "@/hooks/usePaging";
import { recordAll, recordInfo } from "@/api/record";
import { cateTimeListsApi, cateTimeDelApi } from "@/api/cate_time";
import feedback from "@/utils/feedback";
import { merchantCate } from "@/api/merchant";
import EditPopup from "./edit.vue";
const editRef = shallowRef<InstanceType<typeof EditPopup>>();
//
const showEdit = ref(false);
//
const queryParams = reactive({
type_id: "",
});
//
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: cateTimeListsApi,
params: queryParams,
});
//
const handleAdd = async () => {
showEdit.value = true;
await nextTick();
editRef.value?.open("add");
};
//
const handleEdit = async (data: any) => {
showEdit.value = true;
await nextTick();
editRef.value?.open("edit");
editRef.value?.setFormData(data);
};
//
const handleDelete = async (id: number | any[]) => {
await feedback.confirm("确定要删除?");
await cateTimeDelApi({ id });
getLists();
};
//
const merchantData: any = ref([]);
const getMerchantCate = async () => {
merchantData.value = await merchantCate("");
};
getMerchantCate();
getLists();
</script>

View File

@ -1,123 +1,170 @@
<style lang="scss">
.w-80 {
width: 500px;
width: 500px;
}
.form-wrap {
display: flex;
flex-wrap: wrap;
justify-content: center;
flex-direction: column;
align-items: center;
display: flex;
flex-wrap: wrap;
justify-content: center;
flex-direction: column;
align-items: center;
}
</style>
<template>
<div class="article-edit">
<el-card class="!border-none" shadow="never">
<el-page-header :content="$route.meta.title" @back="$router.back()" />
</el-card>
<el-card class="mt-4 !border-none" shadow="never">
<el-form ref="formRef" class="ls-form" :model="formData" label-width="100px" :rules="rules">
<div class="form-wrap">
<el-form-item label="商户名称" prop="mer_name">
<el-input class="w-80" v-model="formData.mer_name" placeholder="请输入商户名称" clearable />
</el-form-item>
<div class="article-edit">
<el-card class="!border-none" shadow="never">
<el-page-header :content="$route.meta.title" @back="$router.back()" />
</el-card>
<el-card class="mt-4 !border-none" shadow="never">
<el-form
ref="formRef"
class="ls-form"
:model="formData"
label-width="100px"
:rules="rules"
>
<div class="form-wrap">
<el-form-item label="商户名称" prop="mer_name">
<el-input
class="w-80"
v-model="formData.mer_name"
placeholder="请输入商户名称"
clearable
/>
</el-form-item>
<el-form-item label="真实姓名" prop="real_name">
<el-input class="w-80" v-model="formData.real_name" placeholder="请输入真实姓名" />
</el-form-item>
<el-form-item label="真实姓名" prop="real_name">
<el-input
class="w-80"
v-model="formData.real_name"
placeholder="请输入真实姓名"
/>
</el-form-item>
<el-form-item label="总采购金额" prop="purchase_amount">
<el-input class="w-80" v-model="formData.purchase_amount" placeholder="请输入总采购金额" readonly />
</el-form-item>
<el-form-item label="总采购金额" prop="purchase_amount">
<el-input
class="w-80"
v-model="formData.purchase_amount"
placeholder="请输入总采购金额"
readonly
/>
</el-form-item>
<el-form-item label="总销售金额" prop="sale_amount">
<el-input class="w-80" v-model="formData.sale_amount" placeholder="请输入总销售金额" readonly />
</el-form-item>
<el-form-item label="总销售金额" prop="sale_amount">
<el-input
class="w-80"
v-model="formData.sale_amount"
placeholder="请输入总销售金额"
readonly
/>
</el-form-item>
<el-form-item label="手机号" prop="service_phone">
<el-input class="w-80" v-model="formData.service_phone" placeholder="请输入手机号" clearable />
</el-form-item>
<el-form-item label="手机号" prop="service_phone">
<el-input
class="w-80"
v-model="formData.service_phone"
placeholder="请输入手机号"
clearable
/>
</el-form-item>
<el-form-item label="评分" prop="product_score">
<el-input class="w-80" v-model="formData.product_score" placeholder="请输入评分" type="number"
maxlength="1" max="5" min="1" clearable />
</el-form-item>
<el-form-item label="评分" prop="product_score">
<el-input
class="w-80"
v-model="formData.product_score"
placeholder="请输入评分"
type="number"
maxlength="1"
max="5"
min="1"
clearable
/>
</el-form-item>
<el-form-item label="店铺类型" prop="type_name">
<el-select class="w-80" v-model="formData.type_name" placeholder="请输入店铺类型">
<el-option :label="item.type_name" :value="item.mer_type_id" v-for="item in merchantData"
:key="item.mer_type_id" />
</el-select>
</el-form-item>
<el-form-item label="店铺类型" prop="type_name">
<el-select
class="w-80"
v-model="formData.type_name"
placeholder="请输入店铺类型"
>
<el-option
:label="item.type_name"
:value="item.mer_type_id"
v-for="item in merchantData"
:key="item.mer_type_id"
/>
</el-select>
</el-form-item>
<el-form-item label="地址" prop="mer_address">
<el-input class="w-80" v-model="formData.mer_address" placeholder="请输入地址" clearable />
</el-form-item>
</div>
</el-form>
</el-card>
<footer-btns>
<el-button type="primary" @click="handleSave">保存</el-button>
</footer-btns>
</div>
<el-form-item label="地址" prop="mer_address">
<el-input
class="w-80"
v-model="formData.mer_address"
placeholder="请输入地址"
clearable
/>
</el-form-item>
</div>
</el-form>
</el-card>
<footer-btns>
<el-button type="primary" @click="handleSave">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup name="articleListsEdit">
import type { FormInstance } from 'element-plus'
import type { FormInstance } from "element-plus";
import { merchantDetail, merchantUpdate, merchantCate } from "@/api/merchant";
import { articleDetail, articleEdit, articleAdd, articleCateAll } from '@/api/article'
const route = useRoute()
const router = useRouter()
const route = useRoute();
const router = useRouter();
const formData = ref({
mer_id: "",//id
mer_name: "",//
mer_avatar: "",//
real_name: "",//
mer_address: "",//
purchase_amount: "",//
sale_amount: "",//
service_phone: "",//
product_score: "",//
type_name: "",//
goods_num: "",//
mer_id: "", //id
mer_name: "", //
mer_avatar: "", //
real_name: "", //
mer_address: "", //
purchase_amount: "", //
sale_amount: "", //
service_phone: "", //
product_score: "", //
type_name: "", //
goods_num: "", //
});
const formRef = shallowRef<FormInstance>()
const formRef = shallowRef<FormInstance>();
const rules = reactive({
mer_name: [{ required: true, message: '请输入商户名称', trigger: 'blur' }],
real_name: [{ required: true, message: '请输入商户姓名', trigger: 'blur' }],
mer_address: [{ required: true, message: '请输入商户地址', trigger: 'blur' }],
service_phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
product_score: [{ required: true, message: '请输入评分', trigger: 'blur' }],
type_name: [{ required: true, message: '请输入店铺类型', trigger: 'blur' }],
})
mer_name: [{ required: true, message: "请输入商户名称", trigger: "blur" }],
real_name: [{ required: true, message: "请输入商户姓名", trigger: "blur" }],
mer_address: [{ required: true, message: "请输入商户地址", trigger: "blur" }],
service_phone: [{ required: true, message: "请输入手机号", trigger: "blur" }],
product_score: [{ required: true, message: "请输入评分", trigger: "blur" }],
type_name: [{ required: true, message: "请输入店铺类型", trigger: "blur" }],
});
const getDetails = async () => {
const data = await merchantDetail({
mer_id: route.query.id
});
const data = await merchantDetail({
mer_id: route.query.id,
});
formData.value = data;
}
formData.value = data;
};
//
const merchantData: any = ref([]);
const getMerchantCate = async () => {
merchantData.value = await merchantCate("");
}
merchantData.value = await merchantCate("");
};
const handleSave = async () => {
await formRef.value?.validate()
if (route.query.id) {
await merchantUpdate(formData.value)
} else {
await articleAdd(formData.value)
}
router.back()
}
await formRef.value?.validate();
if (route.query.id) {
await merchantUpdate(formData.value);
}
router.back();
};
route.query.id && getDetails();
getMerchantCate();

View File

@ -6,8 +6,9 @@
class="mb-[-16px] mt-[16px]"
:model="queryParams"
:inline="true"
label-width="80"
>
<el-form-item label="商户名称">
<el-form-item label="商户名称" prop="mer_name">
<el-input
class="w-[280px]"
v-model="queryParams.mer_name"
@ -17,28 +18,9 @@
/>
</el-form-item>
<el-form-item label="真实姓名">
<el-input
class="w-[280px]"
v-model="queryParams.real_name"
placeholder="请输入真实姓名"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="商户地址">
<el-input
class="w-[280px]"
v-model="queryParams.mer_address"
placeholder="请输入地址"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="店铺类型">
<el-form-item label="店铺类型" prop="type_id">
<el-select
class="w-[280px]"
placeholder="请输入店铺类型"
v-model="queryParams.type_id"
@keyup.enter="resetPage"
@ -51,6 +33,129 @@
/>
</el-select>
</el-form-item>
<el-form-item label="商户分类" prop="category_id">
<el-select
class="w-[280px]"
placeholder="请选择商户分类"
v-model="queryParams.category_id"
@keyup.enter="resetPage"
>
<el-option
v-for="item in categoryList"
:label="item.category_name"
:value="item.merchant_category_id"
:key="item.merchant_category_id"
/>
</el-select>
</el-form-item>
<el-form-item label="是否批发" prop="wholesale">
<el-select
class="w-[280px]"
placeholder="请选择是否批发"
v-model="queryParams.wholesale"
@keyup.enter="resetPage"
>
<el-option label="仅零售" value="0" />
<el-option label="仅批发" value="1" />
<el-option label="零售批发" value="2" />
</el-select>
</el-form-item>
<el-form-item label="商户姓名" prop="real_name">
<el-input
class="w-[280px]"
v-model="queryParams.real_name"
placeholder="请输入商户姓名"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="详细地址" prop="mer_address">
<el-input
class="w-[280px]"
v-model="queryParams.mer_address"
placeholder="请输入详细地址"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="采购金额" prop="purchase_amount">
<el-input
class="w-[280px]"
v-model="queryParams.purchase_amount"
placeholder="请输入采购金额"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="销售金额" prop="sale_amount">
<el-input
class="w-[280px]"
v-model="queryParams.sale_amount"
placeholder="请输入销售金额"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="店铺评分" prop="product_score">
<el-input
class="w-[280px]"
v-model="queryParams.product_score"
placeholder="请输入店铺评分"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="真实姓名" prop="real_name">
<el-input
class="w-[280px]"
v-model="queryParams.real_name"
placeholder="请输入真实姓名"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="区、县" prop="category_id">
<el-select
class="w-[280px]"
placeholder="请选择区、县"
v-model="queryParams.area_id"
@keyup.enter="resetPage"
@change="areaChange"
>
<el-option
v-for="item in areaList"
:label="item.area_name"
:value="item.area_code"
:key="item.area_code"
/>
</el-select>
</el-form-item>
<el-form-item label="镇、街道" prop="street_id">
<el-select
class="w-[280px]"
placeholder="请选择镇、街道"
v-model="queryParams.street_id"
@keyup.enter="resetPage"
>
<el-option
v-for="item in streetList"
:label="item.street_name"
:value="item.street_code"
:key="item.street_code"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
@ -60,6 +165,7 @@
<el-card class="!border-none mt-4" shadow="never">
<div class="toolbar">
<el-button type="primary" @click="onBindBatch" size="small"> 批量绑定 </el-button>
<el-button type="primary" @click="onDownload" size="small">导出</el-button>
</div>
<el-table
@ -70,6 +176,26 @@
@selection-change="onSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column type="expand">
<template #default="props">
<el-form label-position="left" inline>
<el-row style="margin-left: 120px">
<el-col :span="6">
<el-form-item label="跟进时间:" style="margin-bottom: 0px">
{{
(props.row.follow_log && props.row.follow_log.create_time) || "-"
}}
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item label="备注:" style="margin-bottom: 0px">
{{ (props.row.follow_log && props.row.follow_log.remark) || "-" }}
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</el-table-column>
<el-table-column label="商户名称" prop="mer_name" min-width="220" />
<el-table-column label="真实姓名" prop="real_name" min-width="100" />
<el-table-column label="总采购金额" prop="purchase_amount" min-width="100" />
@ -79,11 +205,12 @@
<el-table-column label="店铺类型" prop="type_name" min-width="120" />
<el-table-column label="店铺商品数" prop="goods_num" min-width="110" />
<el-table-column label="地址" prop="mer_address" min-width="220" />
<el-table-column label="操作" width="200" fixed="right">
<el-table-column label="操作" width="240" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['merchant.merchant/edit', 'merchant.merchant/add:edit']"
type="primary"
size="small"
link
>
<router-link
@ -97,20 +224,38 @@
编辑
</router-link>
</el-button>
<el-button
v-perms="['merchant.merchant/share']"
v-perms="['merchant.merchant/edit', 'merchant.merchant/add:edit']"
type="primary"
@click="onBind(row)"
link
size="small"
link
@click="onTraceRecord(row)"
>
商户分配
</el-button>
<el-button type="primary" @click="onMonitor(row)" link size="small">
督导情况
添加跟进记录
</el-button>
<el-dropdown @command="onDropdownClick($event, row)">
<el-button type="primary" link size="small"
>更多操作 <el-icon class="el-icon--right"><arrow-down /></el-icon
></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="mer_share">商户绑定</el-dropdown-item>
<el-dropdown-item command="mer_monitor">督导情况</el-dropdown-item>
<el-dropdown-item command="mer_record">
<router-link
:to="{
path: getRoutePath('record.record/lists'),
query: {
id: row.mer_id,
},
}"
>
跟进记录
</router-link>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>
@ -160,18 +305,18 @@
:async="true"
width="70%"
@confirm="onBindSubmit"
@close="onClose"
@close="onMonitorClose"
>
<el-form ref="formRef" :model="monitorForm" label-width="180px">
<el-row>
<el-col :span="12">
<el-form-item
label="督导师"
prop="supervisor"
prop="store_condition.supervisor"
:rules="{ required: true, message: '督导师不能为空', trigger: 'blur' }"
>
<el-input
v-model="monitorForm.supervisor"
v-model="monitorForm.store_condition.supervisor"
placeholder="请输入督导师"
></el-input>
</el-form-item>
@ -180,11 +325,11 @@
<el-col :span="12">
<el-form-item
label="成活率"
prop="supervisor_rate"
prop="store_condition.survival_rate"
:rules="{ required: true, message: '成活率不能为空', trigger: 'blur' }"
>
<el-input-number
v-model="monitorForm.supervisor_rate"
v-model="monitorForm.store_condition.survival_rate"
placeholder="请输入成活率"
controls-position="right"
:min="0.01"
@ -198,11 +343,11 @@
<el-col :span="12">
<el-form-item
label="督导员"
prop="administrator"
prop="store_condition.administrator"
:rules="{ required: true, message: '督导员不能为空', trigger: 'blur' }"
>
<el-input
v-model="monitorForm.administrator"
v-model="monitorForm.store_condition.administrator"
placeholder="请输入督导员"
></el-input>
</el-form-item>
@ -211,11 +356,11 @@
<el-col :span="12">
<el-form-item
label="成活率"
prop="survival_rate"
prop="store_condition.administrator_rate"
:rules="{ required: true, message: '成活率不能为空', trigger: 'blur' }"
>
<el-input-number
v-model="monitorForm.survival_rate"
v-model="monitorForm.store_condition.administrator_rate"
placeholder="请输入成活率"
controls-position="right"
:min="0.01"
@ -229,11 +374,11 @@
<el-col :span="12">
<el-form-item
label="运营对接人"
prop="operate"
prop="store_condition.operate"
:rules="{ required: true, message: '运营对接人不能为空', trigger: 'blur' }"
>
<el-input
v-model="monitorForm.operate"
v-model="monitorForm.store_condition.operate"
placeholder="请输入运营对接人"
></el-input>
</el-form-item>
@ -242,11 +387,11 @@
<el-col :span="12">
<el-form-item
label="成活率"
prop="operate_rate"
prop="store_condition.operate_rate"
:rules="{ required: true, message: '运营对接人不能为空', trigger: 'blur' }"
>
<el-input-number
v-model="monitorForm.operate_rate"
v-model="monitorForm.store_condition.operate_rate"
placeholder="请输入成活率"
controls-position="right"
:min="0.01"
@ -260,7 +405,7 @@
<el-col :span="12">
<el-form-item
label="监督人商户总体情况"
prop="condition"
prop="store_condition.condition"
:rules="{
required: true,
message: '监督人商户总体情况不能为空',
@ -268,12 +413,84 @@
}"
>
<el-input
v-model="monitorForm.condition"
v-model="monitorForm.store_condition.condition"
placeholder="请输入监督人商户总体情况"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="技术"
prop="store_condition.technology"
:rules="{
required: true,
message: '技术不能为空',
trigger: 'blur',
}"
>
<el-input
v-model="monitorForm.store_condition.technology"
clearable
placeholder="请输入技术"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="财务"
prop="store_condition.finance"
:rules="{
required: true,
message: '财务不能为空',
trigger: 'blur',
}"
>
<el-input
v-model="monitorForm.store_condition.finance"
clearable
placeholder="请输入财务"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="推广"
prop="store_condition.extend"
:rules="{
required: true,
message: '推广不能为空',
trigger: 'blur',
}"
>
<el-input
v-model="monitorForm.store_condition.extend"
clearable
placeholder="请输入推广"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="风控"
prop="store_condition.risk"
:rules="{
required: true,
message: '风控不能为空',
trigger: 'blur',
}"
>
<el-input
v-model="monitorForm.store_condition.risk"
clearable
placeholder="请输入风控"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="商户总更新">
<el-input
@ -593,6 +810,8 @@
</el-row>
</el-form>
</Popup>
<!-- 跟进记录 -->
<edit-popup ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
@ -604,16 +823,24 @@ import {
merchantCate,
storeSuper,
merchantUpdate,
excelApi,
merchantCategoryApi,
merchantAreaListApi,
streetListApi,
saveConditionApi,
recordManApi,
} from "@/api/merchant";
import { usePaging } from "@/hooks/usePaging";
import { useRoute } from "vue-router";
import { getRoutePath } from "@/router";
import feedback from "@/utils/feedback";
import { ref } from "vue";
import Popup from "@/components/popup/index.vue";
import EditPopup from "@/views/record/edit.vue"; //
const monitorRef: any = ref(null); //
const formRef: any = ref(null); //
const popupRef = shallowRef<InstanceType<typeof Popup>>(); //
const popupRef = shallowRef<InstanceType<typeof Popup>>(); //dialog
const tableRef: any = ref(null); //
const emit = defineEmits(["success", "close"]);
@ -626,9 +853,37 @@ const queryParams = reactive({
sale_amount: "",
type_id: "",
product_score: "",
mer_ids: "",
category_id: "",
wholesale: "",
area_id: "",
street_id: "",
});
//
const route = useRoute();
const merIds = route.query.mer_ids || "";
if (merIds) {
queryParams.mer_ids = merIds as string;
}
//
//
const onDropdownClick = (type: any, item: any) => {
switch (type) {
case "mer_share": //
onBind(item);
break;
case "mer_monitor": //
onMonitor(item);
break;
case "mer_record": //
onTraceRecord(item);
break;
}
};
//
const bindForm: any = reactive({
id: "",
merchant_ids: [],
@ -653,6 +908,11 @@ const onBindBatch = async () => {
});
};
//
const onDownload = () => {
excelApi(queryParams).then((res) => {});
};
//
const handleSubmit = async () => {
if (!bindForm.admin_id) return feedback.msgError("请选择子管理员!");
@ -661,20 +921,21 @@ const handleSubmit = async () => {
onClose();
};
// dialog
const onClose = () => {
bindForm.merchant_ids = [];
tableRef.value?.clearSelection();
monitorRef.value?.close();
popupRef.value?.close();
};
//
const selectData = ref<any[]>([]);
const onSelectionChange = (val: any[]) => {
selectData.value = val.map(({ mer_id }) => mer_id);
};
//
const onClose = () => {
bindForm.merchant_ids = [];
tableRef.value?.clearSelection();
};
//
const onMonitorClose = () => {};
//
const onMonitor = async (row: any) => {
let detail = await storeSuper({ mer_id: row.mer_id });
@ -685,7 +946,7 @@ const onMonitor = async (row: any) => {
//
const onBindSubmit = async () => {
await formRef.value?.validate();
await merchantUpdate(monitorForm.value);
await saveConditionApi(monitorForm.value.store_condition);
monitorRef.value?.close();
emit("success");
};
@ -732,31 +993,61 @@ const monitorForm: any = ref({
incomeAllSubsidies: "", //
incomeBalanceSubsidies: "", //
incomeTodaySubsides: "", //
store_condition: {},
});
//
const editRef = shallowRef<InstanceType<typeof EditPopup>>();
//
const showEdit = ref(false);
//
const onTraceRecord = (item: any) => {
showEdit.value = true;
editRef.value?.open("add", item.mer_id);
};
//
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: merchantList,
params: queryParams,
});
//
//
const merchantData: any = ref([]);
const getMerchantCate = async () => {
merchantData.value = await merchantCate("");
};
const categoryList = ref([]);
merchantCategoryApi("").then((res) => {
categoryList.value = res;
});
//
const children: any = ref([]);
const getChildManagement = async () => {
children.value = await childManagement("");
const children = ref([]);
recordManApi("").then((res) => {
children.value = res;
});
//
const areaList = ref([]);
merchantAreaListApi("").then((res) => {
areaList.value = res;
});
//
const streetList = ref([]);
const areaChange = () => {
queryParams.street_id = "";
streetListApi({ area_code: queryParams.area_id }).then((res) => {
streetList.value = res;
});
};
getLists();
//
getChildManagement();
//
getMerchantCate();
</script>
@ -765,7 +1056,7 @@ getMerchantCate();
margin-bottom: 10px;
}
.el-row {
height: 70vh;
max-height: 70vh;
overflow: auto;
}
@ -775,4 +1066,11 @@ getMerchantCate();
.el-input-number {
width: 100%;
}
.el-dropdown {
margin-left: 12px;
vertical-align: middle;
}
.el-table__expanded-cell {
background: #efefef;
}
</style>

342
src/views/monitor/edit.vue Normal file
View File

@ -0,0 +1,342 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="800px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="160px" :rules="formRules">
<el-row>
<el-col :span="12">
<el-form-item label="商户名称" prop="mer_id">
<el-select
placeholder="请选择商户"
v-model="formData.mer_id"
style="width: 100%"
filterable
>
<el-option
v-for="(item, indx) in merListNoPage"
:key="item.mer_id"
:value="item.mer_id"
:label="item.mer_name"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="监督人" prop="supervisor_more">
<el-input
v-model="formData.supervisor_more"
clearable
placeholder="请输入监督人"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="运营人员" prop="operate">
<el-input
v-model="formData.operate"
clearable
placeholder="请输入运营人员"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="运营成活率" prop="operate_rate">
<el-input-number
v-model="formData.operate_rate"
placeholder="请输入运营成活率"
controls-position="right"
:min="0"
:max="100"
:step="1"
:precision="2"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导师" prop="supervisor">
<el-input
v-model="formData.supervisor"
clearable
placeholder="请输入督导师"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导师成活率" prop="survival_rate">
<el-input-number
v-model="formData.survival_rate"
placeholder="请输入督导师成活率"
controls-position="right"
:min="0"
:max="100"
:step="1"
:precision="2"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导员" prop="administrator">
<el-input
v-model="formData.administrator"
clearable
placeholder="请输入督导员"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导员成活率" prop="administrator_rate">
<el-input-number
v-model="formData.administrator_rate"
placeholder="请输入督导员成活率"
controls-position="right"
:min="0"
:max="100"
:step="1"
:precision="2"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="监督人商户总体情况" prop="condition">
<el-input
v-model="formData.condition"
clearable
placeholder="请输入监督人商户总体情况"
type="textarea"
:rows="3"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="技术" prop="technology">
<el-input
v-model="formData.technology"
clearable
placeholder="请输入技术"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="财务" prop="finance">
<el-input v-model="formData.finance" clearable placeholder="请输入财务" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="推广" prop="extend">
<el-input v-model="formData.extend" clearable placeholder="请输入推广" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="风控" prop="risk">
<el-input v-model="formData.risk" clearable placeholder="请输入风控" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup name="recordEdit">
import type { FormInstance } from "element-plus";
import Popup from "@/components/popup/index.vue";
import { merchantListNoPage } from "@/api/merchant";
import { monitorAddApi, monitorEditApi, monitorDetailApi } from "@/api/monitor";
import type { PropType } from "vue";
const emit = defineEmits(["success", "close"]);
const formRef = shallowRef<FormInstance>();
const popupRef = shallowRef<InstanceType<typeof Popup>>();
const mode = ref("add");
//
const popupTitle = computed(() => {
return mode.value == "edit" ? "编辑督导记录" : "新增督导记录";
});
//
const formData = reactive({
id: "",
admin_id: "",
mer_id: "",
operate: "",
operate_rate: 0,
supervisor: "",
survival_rate: 0,
administrator: "",
administrator_rate: 0,
supervisor_more: "",
technology: "",
finance: "",
extend: "",
risk: "",
condition: "",
});
//
const formRules = reactive<any>({
mer_id: [
{
required: true,
message: "请选择商户",
trigger: ["change"],
},
],
operate: [
{
required: true,
message: "请输入运营人员",
trigger: ["change"],
},
],
operate_rate: [
{
required: true,
message: "请输入运营成活率",
trigger: ["change"],
},
],
supervisor: [
{
required: true,
message: "请输入督导师",
trigger: ["change"],
},
],
survival_rate: [
{
required: true,
message: "请输入督导成活率",
trigger: ["change"],
},
],
administrator: [
{
required: true,
message: "请输入督导员",
trigger: ["change"],
},
],
administrator_rate: [
{
required: true,
message: "请输入督导成活率",
trigger: ["change"],
},
],
supervisor_more: [
{
required: true,
message: "请输入监督人",
trigger: ["change"],
},
],
technology: [
{
required: true,
message: "请输入技术",
trigger: ["change"],
},
],
finance: [
{
required: true,
message: "请输入财务",
trigger: ["change"],
},
],
extend: [
{
required: true,
message: "请输入推广",
trigger: ["change"],
},
],
risk: [
{
required: true,
message: "请输入风控",
trigger: ["change"],
},
],
condition: [
{
required: true,
message: "请输入监督人商户总体情况",
trigger: ["change"],
},
],
});
//
const setFormData = async (data: Record<any, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
//
const merListNoPage: any = ref([]);
merchantListNoPage("").then((rs) => {
merListNoPage.value = rs;
});
const getDetail = async (row: Record<string, any>) => {
const data = await monitorDetailApi({
id: row.id,
});
setFormData(data);
};
//
const handleSubmit = async () => {
await formRef.value?.validate();
const data = { ...formData };
mode.value == "edit" ? await monitorEditApi(data) : await monitorAddApi(data);
popupRef.value?.close();
emit("success");
};
//
const open = (type = "add") => {
mode.value = type;
popupRef.value?.open();
};
//
const handleClose = () => {
emit("close");
};
defineExpose({
open,
setFormData,
getDetail,
});
</script>
<style lang="scss">
.el-input__wrapper,
.el-input-number {
width: 100%;
}
</style>

259
src/views/monitor/index.vue Normal file
View File

@ -0,0 +1,259 @@
<template>
<div>
<el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline label-width="80">
<el-form-item label="店铺类型" prop="mer_id">
<el-select
class="w-[280px]"
placeholder="请输入店铺类型"
v-model="queryParams.mer_id"
@keyup.enter="resetPage"
>
<el-option
v-for="item in merchantData"
:label="item.type_name"
:value="item.mer_type_id"
:key="item.mer_type_id"
/>
</el-select>
</el-form-item>
<el-form-item label="监督人" prop="supervisor_more">
<el-input
class="w-[280px]"
v-model="queryParams.supervisor_more"
placeholder="请输入监督人"
/>
</el-form-item>
<el-form-item label="运营" prop="operate">
<el-input
class="w-[280px]"
v-model="queryParams.operate"
placeholder="请输入运营人姓名"
/>
</el-form-item>
<el-form-item label="督导师" prop="supervisor">
<el-input
class="w-[280px]"
v-model="queryParams.supervisor"
placeholder="请输入督导师"
/>
</el-form-item>
<el-form-item label="督导员" prop="administrator">
<el-input
class="w-[280px]"
v-model="queryParams.administrator"
placeholder="请输入督导员"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<el-button v-perms="['monitor.monitor/add']" type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column
label="商户名称"
prop="merchant_name"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
label="运营"
prop="operate"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="成活率"
prop="operate_rate"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="督导师"
prop="supervisor"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="成活率"
prop="survival_rate"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="督导员"
prop="administrator"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="成活率"
prop="administrator_rate"
show-overflow-tooltip
/>
<el-table-column
label="监督人商户总体情况"
prop="condition"
min-width="200"
show-overflow-tooltip
/>
<el-table-column
label="监督人"
prop="supervisor_more"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="技术"
prop="technology"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="财务"
prop="finance"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="推广"
prop="extend"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="风控"
prop="risk"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="创建管理员"
prop="admin_name"
min-width="160"
show-overflow-tooltip
/>
<el-table-column
label="创建时间"
prop="create_time"
min-width="180"
show-overflow-tooltip
/>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['record.record/edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['record.record/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup
v-if="showEdit"
ref="editRef"
@success="getLists"
@close="showEdit = false"
/>
</div>
</template>
<script lang="ts" setup name="recordLists">
import { usePaging } from "@/hooks/usePaging";
import { monitorListApi, monitorDelApi } from "@/api/monitor";
import { merchantCate } from "@/api/merchant";
import { timeFormat } from "@/utils/util";
import feedback from "@/utils/feedback";
import EditPopup from "./edit.vue";
const editRef = shallowRef<InstanceType<typeof EditPopup>>();
//
const showEdit = ref(false);
//
const queryParams = reactive({
mer_id: "",
operate: "",
supervisor: "",
administrator: "",
supervisor_more: "",
});
//
const selectData = ref<any[]>([]);
//
const handleSelectionChange = (val: any[]) => {
selectData.value = val.map(({ id }) => id);
};
//
const merchantData: any = ref([]);
const getMerchantCate = async () => {
merchantData.value = await merchantCate("");
};
//
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: monitorListApi,
params: queryParams,
});
//
const handleAdd = async () => {
showEdit.value = true;
await nextTick();
editRef.value?.open("add");
};
//
const handleEdit = async (data: any) => {
showEdit.value = true;
await nextTick();
editRef.value?.open("edit");
editRef.value?.setFormData(data);
};
//
const handleDelete = async (id: number | any[]) => {
await feedback.confirm("确定要删除?");
await monitorDelApi({ id });
getLists();
};
getLists();
getMerchantCate();
</script>

View File

@ -1,159 +1,217 @@
<template>
<div class="edit-popup">
<popup ref="popupRef" :title="popupTitle" :async="true" width="550px" @confirm="handleSubmit"
@close="handleClose">
<el-form ref="formRef" :model="formData" label-width="90px" :rules="formRules">
<el-form-item label="主题" prop="theme">
<el-input v-model="formData.theme" clearable placeholder="请输入主题" />
</el-form-item>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="550px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="90px" :rules="formRules">
<el-form-item label="主题" prop="theme">
<el-input v-model="formData.theme" clearable placeholder="请输入主题" />
</el-form-item>
<el-form-item label="商户名称" prop="merchant_id">
<el-select placeholder="请选择商户" v-model="formData.merchant_id" style="width:100%;">
<el-option v-for="(item, indx) in recordData" :key="item.id" :value="item.id"
:label="item.name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="商户名称" prop="merchant_id">
<el-select
placeholder="请选择商户"
v-model="formData.merchant_id"
style="width: 100%"
filterable
>
<el-option
v-for="(item, indx) in merListNoPage"
:key="item.mer_id"
:value="item.mer_id"
:label="item.mer_name"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="记录类型" prop="rid">
<el-select placeholder="请选择记录类型" v-model="formData.rid" style="width:100%;">
<el-option v-for="(item, indx) in recordData" :key="item.id" :value="item.id"
:label="item.name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="记录人" prop="admin_id">
<el-select placeholder="请选择记录人" v-model="formData.admin_id" style="width:100%;">
<el-option v-for="(item, indx) in recordInfo" :key="item.id" :value="item.id"
:label="item.name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="记录类型" prop="rid">
<el-select
placeholder="请选择记录类型"
v-model="formData.rid"
style="width: 100%"
>
<el-option
v-for="(item, indx) in recordList"
:key="item.id"
:value="item.id"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="跟进时间" prop="flow_time">
<el-date-picker v-model="formData.flow_time" type="date" placeholder="请选择跟进时间" style="width: 100%;">
</el-date-picker>
</el-form-item>
<el-form-item label="记录人" prop="admin_id">
<el-select
placeholder="请选择记录人"
v-model="formData.admin_id"
style="width: 100%"
>
<el-option
v-for="(item, indx) in recordInfoList"
:key="item.id"
:value="item.id"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" clearable placeholder="请输入备注" />
</el-form-item>
</el-form>
</popup>
</div>
<el-form-item label="跟进时间" prop="flow_time">
<el-date-picker
v-model="formData.flow_time"
type="date"
placeholder="请选择跟进时间"
style="width: 100%"
>
</el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" clearable placeholder="请输入备注" />
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup name="recordEdit">
import type { FormInstance } from 'element-plus'
import Popup from '@/components/popup/index.vue'
import { apiRecordAdd, apiRecordEdit, apiRecordDetail } from '@/api/record'
import { timeFormat } from '@/utils/util'
import type { PropType } from 'vue';
import { defineProps } from 'vue'
defineProps({
recordData: {
type: Array as PropType<any[]>,
default: () => []
},
recordInfo: {
type: Array as PropType<any[]>,
default: () => []
}
})
const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>()
const mode = ref('add')
import type { FormInstance } from "element-plus";
import Popup from "@/components/popup/index.vue";
import {
apiRecordAdd,
apiRecordEdit,
apiRecordDetail,
recordAll,
recordInfo,
} from "@/api/record";
import { merchantListNoPage } from "@/api/merchant";
import { getCurrentInstance,type ComponentInternalInstance ,onMounted} from 'vue';
const emit = defineEmits(["success", "close"]);
const formRef = shallowRef<FormInstance>();
const popupRef = shallowRef<InstanceType<typeof Popup>>();
const mode = ref("add");
//
const popupTitle = computed(() => {
return mode.value == 'edit' ? '编辑跟踪记录表' : '新增跟踪记录表'
})
return mode.value == "edit" ? "编辑跟踪记录" : "新增跟踪记录";
});
//
const formData = reactive({
id: '',
theme: '',
rid: '',
admin_id: '',
remark: '',
flow_time: '',
merchant_id: ''
})
id: "",
theme: "",
rid: "",
admin_id: "",
remark: "",
flow_time: "",
merchant_id: "",
});
//
const formRules = reactive<any>({
theme: [{
required: true,
message: '请输入主题',
trigger: ['blur']
}],
rid: [{
required: true,
message: '请选择商户记录类型',
trigger: ['change']
}],
admin_id: [{
required: true,
message: '请选择商户记录人',
trigger: ['change']
}],
merchant_id: [{
required: true,
message: '请选择商户',
trigger: ['change']
}],
})
theme: [
{
required: true,
message: "请输入主题",
trigger: ["blur"],
},
],
rid: [
{
required: true,
message: "请选择商户记录类型",
trigger: ["change"],
},
],
admin_id: [
{
required: true,
message: "请选择商户记录人",
trigger: ["change"],
},
],
merchant_id: [
{
required: true,
message: "请选择商户",
trigger: ["change"],
},
],
});
//
const setFormData = async (data: Record<any, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key]
}
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
}
};
//
const recordList: any = ref([]);
recordAll("").then((res) => {
recordList.value = res;
});
//
const recordInfoList: any = ref([]);
recordInfo("").then((res) => {
recordInfoList.value = res;
});
//
const merListNoPage: any = ref([]);
merchantListNoPage("").then((rs) => {
merListNoPage.value = rs;
});
const getDetail = async (row: Record<string, any>) => {
const data = await apiRecordDetail({
id: row.id
})
setFormData(data)
}
const data = await apiRecordDetail({
id: row.id,
});
setFormData(data);
};
//
const handleSubmit = async () => {
await formRef.value?.validate()
const data = { ...formData, }
mode.value == 'edit'
? await apiRecordEdit(data)
: await apiRecordAdd(data)
popupRef.value?.close()
emit('success')
}
await formRef.value?.validate();
const data = { ...formData };
mode.value == "edit" ? await apiRecordEdit(data) : await apiRecordAdd(data);
popupRef.value?.close();
emit("success");
const {appContext} = getCurrentInstance()as ComponentInternalInstance;
appContext.config.globalProperties.$mitt.emit("selfEvent");
};
//
const open = (type = 'add') => {
mode.value = type
popupRef.value?.open()
}
const open = (type = "add", merId = "") => {
mode.value = type;
popupRef.value?.open();
if (merId) {
formData.merchant_id = merId;
}
};
//
const handleClose = () => {
emit('close')
}
emit("close");
};
defineExpose({
open,
setFormData,
getDetail
})
open,
setFormData,
getDetail,
});
</script>
<style lang="scss">
.el-input__wrapper {
width: 100%;
width: 100%;
}
</style>

View File

@ -1,151 +1,238 @@
<template>
<div>
<el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="主题" prop="theme">
<el-input class="w-[280px]" v-model="queryParams.theme" clearable placeholder="请输入主题" />
</el-form-item>
<el-form-item label="记录类型" prop="rid">
<el-select placeholder="请选择记录类型" v-model="queryParams.rid" class="w-[280px]">
<el-option v-for="item in recordList" :key="item.id" :value="item.id"
:label="item.name"></el-option>
</el-select>
</el-form-item>
<el-form-item label="记录人" prop="admin_id">
<el-select placeholder="请选择记录人" v-model="queryParams.admin_id" class="w-[280px]">
<el-option v-for="item in recordInfoList" :key="item.id" :value="item.id"
:label="item.name"></el-option>
</el-select>
</el-form-item>
<div>
<el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="商户名称" prop="merchant_id">
<el-select
placeholder="请选择商户"
v-model="queryParams.merchant_id"
class="w-[280px]"
filterable
>
<el-option
v-for="(item, indx) in merListNoPage"
:key="item.mer_id"
:value="item.mer_id + ''"
:label="item.mer_name"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="商户" prop="merchant_id">
<el-input class="w-[280px]" v-model="queryParams.merchant_id" clearable placeholder="请选择商户" />
</el-form-item>
<el-form-item label="跟进主题" prop="theme">
<el-input
class="w-[280px]"
v-model="queryParams.theme"
clearable
placeholder="请输入主题"
/>
</el-form-item>
<el-form-item label="跟进时间" prop="flow_time">
<el-date-picker class="w-[280px]" v-model="queryParams.flow_time" type="date" placeholder="请选择跟进时间">
</el-date-picker>
</el-form-item>
<el-form-item label="记录类型" prop="rid">
<el-select
placeholder="请选择记录类型"
v-model="queryParams.rid"
class="w-[280px]"
>
<el-option
v-for="item in recordList"
:key="item.id"
:value="item.id"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<el-button v-perms="['record.record/add']" type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<el-button v-perms="['record.record/delete']" :disabled="!selectData.length"
@click="handleDelete(selectData)">
<el-form-item label="记录人" prop="admin_id">
<el-select
placeholder="请选择记录人"
v-model="queryParams.admin_id"
class="w-[280px]"
>
<el-option
v-for="item in recordInfoList"
:key="item.id"
:value="item.id"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="跟进时间" prop="flow_time">
<el-date-picker
class="w-[280px]"
v-model="queryParams.flow_time"
type="date"
placeholder="请选择跟进时间"
>
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<el-button v-perms="['record.record/add']" type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<el-button
v-perms="['record.record/delete']"
:disabled="!selectData.length"
@click="handleDelete(selectData)"
>
删除
</el-button>
<div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column
label="商户名称"
prop="merchant_name"
min-width="200"
show-overflow-tooltip
/>
<el-table-column label="主题" prop="theme" show-overflow-tooltip />
<el-table-column label="记录类型" prop="cate_name" show-overflow-tooltip />
<el-table-column label="记录人" prop="admin_info" show-overflow-tooltip />
<el-table-column
label="跟进时间"
prop="flow_time"
min-width="160"
show-overflow-tooltip
/>
<el-table-column
label="创建时间"
prop="create_time"
min-width="160"
show-overflow-tooltip
/>
<el-table-column
label="备注"
prop="remark"
min-width="150"
show-overflow-tooltip
/>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['record.record/edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['record.record/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
<div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="主题" prop="theme" show-overflow-tooltip />
<el-table-column label="记录类型" prop="cate_name" show-overflow-tooltip />
<el-table-column label="记录人" prop="admin_info" show-overflow-tooltip />
<el-table-column label="商户" prop="merchant_name" show-overflow-tooltip />
<el-table-column label="备注" prop="remark" show-overflow-tooltip />
<el-table-column label="更进时间" prop="flow_time" show-overflow-tooltip />
<el-table-column label="创建时间" prop="create_time" show-overflow-tooltip />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button v-perms="['record.record/edit']" type="primary" link @click="handleEdit(row)">
编辑
</el-button>
<el-button v-perms="['record.record/delete']" type="danger" link
@click="handleDelete(row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup v-if="showEdit" ref="editRef" :record-info="recordInfoList" :record-data="recordList"
@success="getLists" @close="showEdit = false" />
</div>
<edit-popup
v-if="showEdit"
ref="editRef"
:record-info="recordInfoList"
:record-data="recordList"
@success="getLists"
@close="showEdit = false"
/>
</div>
</template>
<script lang="ts" setup name="recordLists">
import { usePaging } from '@/hooks/usePaging'
import { useDictData } from '@/hooks/useDictOptions'
import { apiRecordLists, apiRecordDelete, recordAll, recordInfo } from '@/api/record'
import { timeFormat } from '@/utils/util'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
import { usePaging } from "@/hooks/usePaging";
import { apiRecordLists, apiRecordDelete, recordAll, recordInfo } from "@/api/record";
import { merchantListNoPage } from "@/api/merchant";
import feedback from "@/utils/feedback";
import EditPopup from "./edit.vue";
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const route = useRoute();
const editRef = shallowRef<InstanceType<typeof EditPopup>>();
//
const showEdit = ref(false);
//
const queryParams = reactive({
theme: '',
rid: '',
admin_id: '',
merchant_id: '',
remark: '',
flow_time: '',
})
theme: "",
rid: "",
admin_id: "",
merchant_id: "",
remark: "",
flow_time: "",
});
//
const selectData = ref<any[]>([])
const selectData = ref<any[]>([]);
//
const handleSelectionChange = (val: any[]) => {
selectData.value = val.map(({ id }) => id)
}
selectData.value = val.map(({ id }) => id);
};
//
const recordList: any = ref([]);
recordAll("").then(res => {
recordList.value = res;
})
recordAll("").then((res) => {
recordList.value = res;
});
//
const recordInfoList: any = ref([]);
recordInfo("").then(res => {
recordInfoList.value = res;
})
recordInfo("").then((res) => {
recordInfoList.value = res;
});
//
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: apiRecordLists,
params: queryParams
})
fetchFun: apiRecordLists,
params: queryParams,
});
//
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
showEdit.value = true;
await nextTick();
editRef.value?.open("add");
};
//
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit')
editRef.value?.setFormData(data)
}
showEdit.value = true;
await nextTick();
editRef.value?.open("edit");
editRef.value?.setFormData(data);
};
//
const handleDelete = async (id: number | any[]) => {
await feedback.confirm('确定要删除?')
await apiRecordDelete({ id })
getLists()
}
await feedback.confirm("确定要删除?");
await apiRecordDelete({ id });
getLists();
};
getLists()
//
const merListNoPage: any = ref([]);
merchantListNoPage("").then((rs) => {
merListNoPage.value = rs;
});
const id = route.query.id;
if (id) queryParams.merchant_id = id;
getLists();
</script>

View File

@ -0,0 +1,342 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="800px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="160px" :rules="formRules">
<el-row>
<el-col :span="12">
<el-form-item label="商户名称" prop="mer_id">
<el-select
placeholder="请选择商户"
v-model="formData.mer_id"
style="width: 100%"
filterable
>
<el-option
v-for="(item, indx) in merListNoPage"
:key="item.mer_id"
:value="item.mer_id"
:label="item.mer_name"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="监督人" prop="supervisor_more">
<el-input
v-model="formData.supervisor_more"
clearable
placeholder="请输入监督人"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="运营人员" prop="operate">
<el-input
v-model="formData.operate"
clearable
placeholder="请输入运营人员"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="运营成活率" prop="operate_rate">
<el-input-number
v-model="formData.operate_rate"
placeholder="请输入运营成活率"
controls-position="right"
:min="0"
:max="100"
:step="1"
:precision="2"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导师" prop="supervisor">
<el-input
v-model="formData.supervisor"
clearable
placeholder="请输入督导师"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导师成活率" prop="survival_rate">
<el-input-number
v-model="formData.survival_rate"
placeholder="请输入督导师成活率"
controls-position="right"
:min="0"
:max="100"
:step="1"
:precision="2"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导员" prop="administrator">
<el-input
v-model="formData.administrator"
clearable
placeholder="请输入督导员"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="督导员成活率" prop="administrator_rate">
<el-input-number
v-model="formData.administrator_rate"
placeholder="请输入督导员成活率"
controls-position="right"
:min="0"
:max="100"
:step="1"
:precision="2"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="监督人商户总体情况" prop="condition">
<el-input
v-model="formData.condition"
clearable
placeholder="请输入监督人商户总体情况"
type="textarea"
:rows="3"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="技术" prop="technology">
<el-input
v-model="formData.technology"
clearable
placeholder="请输入技术"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="财务" prop="finance">
<el-input v-model="formData.finance" clearable placeholder="请输入财务" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="推广" prop="extend">
<el-input v-model="formData.extend" clearable placeholder="请输入推广" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="风控" prop="risk">
<el-input v-model="formData.risk" clearable placeholder="请输入风控" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup name="recordEdit">
import type { FormInstance } from "element-plus";
import Popup from "@/components/popup/index.vue";
import { merchantListNoPage } from "@/api/merchant";
import { monitorAddApi, monitorEditApi, monitorDetailApi } from "@/api/monitor";
import type { PropType } from "vue";
const emit = defineEmits(["success", "close"]);
const formRef = shallowRef<FormInstance>();
const popupRef = shallowRef<InstanceType<typeof Popup>>();
const mode = ref("add");
//
const popupTitle = computed(() => {
return mode.value == "edit" ? "编辑督导记录" : "新增督导记录";
});
//
const formData = reactive({
id: "",
admin_id: "",
mer_id: "",
operate: "",
operate_rate: 0,
supervisor: "",
survival_rate: 0,
administrator: "",
administrator_rate: 0,
supervisor_more: "",
technology: "",
finance: "",
extend: "",
risk: "",
condition: "",
});
//
const formRules = reactive<any>({
mer_id: [
{
required: true,
message: "请选择商户",
trigger: ["change"],
},
],
operate: [
{
required: true,
message: "请输入运营人员",
trigger: ["change"],
},
],
operate_rate: [
{
required: true,
message: "请输入运营成活率",
trigger: ["change"],
},
],
supervisor: [
{
required: true,
message: "请输入督导师",
trigger: ["change"],
},
],
survival_rate: [
{
required: true,
message: "请输入督导成活率",
trigger: ["change"],
},
],
administrator: [
{
required: true,
message: "请输入督导员",
trigger: ["change"],
},
],
administrator_rate: [
{
required: true,
message: "请输入督导成活率",
trigger: ["change"],
},
],
supervisor_more: [
{
required: true,
message: "请输入监督人",
trigger: ["change"],
},
],
technology: [
{
required: true,
message: "请输入技术",
trigger: ["change"],
},
],
finance: [
{
required: true,
message: "请输入财务",
trigger: ["change"],
},
],
extend: [
{
required: true,
message: "请输入推广",
trigger: ["change"],
},
],
risk: [
{
required: true,
message: "请输入风控",
trigger: ["change"],
},
],
condition: [
{
required: true,
message: "请输入监督人商户总体情况",
trigger: ["change"],
},
],
});
//
const setFormData = async (data: Record<any, any>) => {
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
//
const merListNoPage: any = ref([]);
merchantListNoPage("").then((rs) => {
merListNoPage.value = rs;
});
const getDetail = async (row: Record<string, any>) => {
const data = await monitorDetailApi({
id: row.id,
});
setFormData(data);
};
//
const handleSubmit = async () => {
await formRef.value?.validate();
const data = { ...formData };
mode.value == "edit" ? await monitorEditApi(data) : await monitorAddApi(data);
popupRef.value?.close();
emit("success");
};
//
const open = (type = "add") => {
mode.value = type;
popupRef.value?.open();
};
//
const handleClose = () => {
emit("close");
};
defineExpose({
open,
setFormData,
getDetail,
});
</script>
<style lang="scss">
.el-input__wrapper,
.el-input-number {
width: 100%;
}
</style>

View File

@ -0,0 +1,259 @@
<template>
<div>
<el-card class="!border-none mb-4" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline label-width="80">
<el-form-item label="店铺类型" prop="mer_id">
<el-select
class="w-[280px]"
placeholder="请输入店铺类型"
v-model="queryParams.mer_id"
@keyup.enter="resetPage"
>
<el-option
v-for="item in merchantData"
:label="item.type_name"
:value="item.mer_type_id"
:key="item.mer_type_id"
/>
</el-select>
</el-form-item>
<el-form-item label="监督人" prop="supervisor_more">
<el-input
class="w-[280px]"
v-model="queryParams.supervisor_more"
placeholder="请输入监督人"
/>
</el-form-item>
<el-form-item label="运营" prop="operate">
<el-input
class="w-[280px]"
v-model="queryParams.operate"
placeholder="请输入运营人姓名"
/>
</el-form-item>
<el-form-item label="督导师" prop="supervisor">
<el-input
class="w-[280px]"
v-model="queryParams.supervisor"
placeholder="请输入督导师"
/>
</el-form-item>
<el-form-item label="督导员" prop="administrator">
<el-input
class="w-[280px]"
v-model="queryParams.administrator"
placeholder="请输入督导员"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
<el-button v-perms="['monitor.monitor/add']" type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
<div class="mt-4">
<el-table :data="pager.lists" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column
label="商户名称"
prop="merchant_name"
min-width="180"
show-overflow-tooltip
/>
<el-table-column
label="运营"
prop="operate"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="成活率"
prop="operate_rate"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="督导师"
prop="supervisor"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="成活率"
prop="survival_rate"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="督导员"
prop="administrator"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="成活率"
prop="administrator_rate"
show-overflow-tooltip
/>
<el-table-column
label="监督人商户总体情况"
prop="condition"
min-width="200"
show-overflow-tooltip
/>
<el-table-column
label="监督人"
prop="supervisor_more"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="技术"
prop="technology"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="财务"
prop="finance"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="推广"
prop="extend"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="风控"
prop="risk"
min-width="120"
show-overflow-tooltip
/>
<el-table-column
label="创建管理员"
prop="admin_name"
min-width="160"
show-overflow-tooltip
/>
<el-table-column
label="创建时间"
prop="create_time"
min-width="180"
show-overflow-tooltip
/>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['record.record/edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['record.record/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup
v-if="showEdit"
ref="editRef"
@success="getLists"
@close="showEdit = false"
/>
</div>
</template>
<script lang="ts" setup name="recordLists">
import { usePaging } from "@/hooks/usePaging";
import { monitorListApi, monitorDelApi } from "@/api/monitor";
import { merchantCate } from "@/api/merchant";
import { timeFormat } from "@/utils/util";
import feedback from "@/utils/feedback";
import EditPopup from "./edit.vue";
const editRef = shallowRef<InstanceType<typeof EditPopup>>();
//
const showEdit = ref(false);
//
const queryParams = reactive({
mer_id: "",
operate: "",
supervisor: "",
administrator: "",
supervisor_more: "",
});
//
const selectData = ref<any[]>([]);
//
const handleSelectionChange = (val: any[]) => {
selectData.value = val.map(({ id }) => id);
};
//
const merchantData: any = ref([]);
const getMerchantCate = async () => {
merchantData.value = await merchantCate("");
};
//
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: monitorListApi,
params: queryParams,
});
//
const handleAdd = async () => {
showEdit.value = true;
await nextTick();
editRef.value?.open("add");
};
//
const handleEdit = async (data: any) => {
showEdit.value = true;
await nextTick();
editRef.value?.open("edit");
editRef.value?.setFormData(data);
};
//
const handleDelete = async (id: number | any[]) => {
await feedback.confirm("确定要删除?");
await monitorDelApi({ id });
getLists();
};
getLists();
getMerchantCate();
</script>

View File

@ -1,119 +1,136 @@
<template>
<div class="workbench">
<div class="lg:flex">
<el-card class="!border-none mb-4 lg:mr-4 lg:w-[350px]" shadow="never">
<template #header>
<span class="card-title">版本信息</span>
</template>
<div>
<div class="flex leading-9">
<div class="w-20">平台名称</div>
<span> {{ workbenchData.version.name }}</span>
</div>
<div class="flex leading-9">
<div class="w-20">当前版本</div>
<span> {{ workbenchData.version.version }}</span>
</div>
<div class="flex leading-9">
<div class="w-20">获取渠道</div>
<div>
<a :href="workbenchData.version.channel.website" target="_blank">
<el-button type="success" size="small">官网</el-button>
</a>
<a class="ml-3" :href="workbenchData.version.channel.gitee" target="_blank">
<el-button type="danger" size="small">Gitee</el-button>
</a>
</div>
</div>
</div>
</el-card>
<el-card class="!border-none mb-4 flex-1" shadow="never">
<template #header>
<div>
<span class="card-title">今日数据</span>
<span class="text-tx-secondary text-xs ml-4">
更新时间{{ workbenchData.today.time }}
</span>
</div>
</template>
<div class="workbench">
<div class="lg:flex">
<el-card class="!border-none mb-4 lg:mr-4 lg:w-[350px]" shadow="never">
<template #header>
<span class="card-title">版本信息</span>
</template>
<div>
<div class="flex leading-9">
<div class="w-20">平台名称</div>
<span> {{ workbenchData.version.name }}</span>
</div>
<div class="flex leading-9">
<div class="w-20">当前版本</div>
<span> {{ workbenchData.version.version }}</span>
</div>
<div class="flex leading-9">
<div class="w-20">获取渠道</div>
<div>
<a :href="workbenchData.version.channel.website" target="_blank">
<el-button type="success" size="small">官网</el-button>
</a>
<a class="ml-3" :href="workbenchData.version.channel.gitee" target="_blank">
<el-button type="danger" size="small">Gitee</el-button>
</a>
</div>
</div>
</div>
</el-card>
<el-card class="!border-none mb-4 flex-1" shadow="never">
<template #header>
<div>
<span class="card-title">今日数据</span>
<span class="text-tx-secondary text-xs ml-4">
更新时间{{ workbenchData.today.time }}
</span>
</div>
</template>
<div class="flex flex-wrap">
<div class="w-1/2 md:w-1/4">
<div class="leading-10">本周订单总数</div>
<div class="text-6xl">{{ merchantInfoData.order.nowWeekOrders }}</div>
<!-- <div class="text-tx-secondary text-xs">
<div class="flex flex-wrap">
<div class="w-1/2 md:w-1/4">
<div class="leading-10">本周订单总数</div>
<div class="text-6xl">{{ merchantInfoData.order.nowWeekOrders }}</div>
<!-- <div class="text-tx-secondary text-xs">
{{ workbenchData.today.total_sales }}
</div> -->
</div>
<div class="w-1/2 md:w-1/4">
<div class="leading-10">上周订单总数</div>
<div class="text-6xl">{{ merchantInfoData.order.lastWeekOrders }}</div>
<!-- <div class="text-tx-secondary text-xs">
</div>
<div class="w-1/2 md:w-1/4">
<div class="leading-10">上周订单总数</div>
<div class="text-6xl">{{ merchantInfoData.order.lastWeekOrders }}</div>
<!-- <div class="text-tx-secondary text-xs">
{{ workbenchData.today.order_sum }}
</div> -->
</div>
<div class="w-1/2 md:w-1/4">
<div class="leading-10">本周销售总额()</div>
<div class="text-6xl">{{ merchantInfoData.amount.nowWeekAmount }}</div>
<!-- <div class="text-tx-secondary text-xs">
</div>
<div class="w-1/2 md:w-1/4">
<div class="leading-10">本周销售总额()</div>
<div class="text-6xl">{{ merchantInfoData.amount.nowWeekAmount }}</div>
<!-- <div class="text-tx-secondary text-xs">
{{ workbenchData.today.total_new_user }}
</div> -->
</div>
<div class="w-1/2 md:w-1/4">
<div class="leading-10">上周销售总额()</div>
<div class="text-6xl">{{ merchantInfoData.amount.lastWeekAmount }}</div>
<!-- <div class="text-tx-secondary text-xs">
</div>
<div class="w-1/2 md:w-1/4">
<div class="leading-10">上周销售总额()</div>
<div class="text-6xl">{{ merchantInfoData.amount.lastWeekAmount }}</div>
<!-- <div class="text-tx-secondary text-xs">
{{ workbenchData.today.total_visitor }}
</div> -->
</div>
</div>
</el-card>
</div>
<div class="function mb-4">
<el-card class="flex-1 !border-none" shadow="never">
<template #header>
<span>常用功能</span>
</template>
<div class="flex flex-wrap">
<div v-for="item in workbenchData.menu" class="md:w-[12.5%] w-1/4 flex flex-col items-center"
:key="item">
<router-link :to="item.url" class="mb-3 flex flex-col items-center">
<image-contain width="40px" height="40px" :src="item?.image" />
<div class="mt-2">{{ item.name }}</div>
</router-link>
</div>
</div>
</el-card>
</div>
<div class="md:flex">
<el-card class="flex-1 !border-none md:mr-4 mb-4" shadow="never">
<template #header>
<span>本周商品销售数量</span>
</template>
<div>
<v-charts style="height: 350px" :option="merchantInfoData.echartOptionNowWeek" :autoresize="true" />
</div>
</el-card>
</div>
<div class="md:flex">
<el-card class="flex-1 !border-none md:mr-4 mb-4" shadow="never">
<template #header>
<span>上周周商品销售数量</span>
</template>
<div>
<v-charts style="height: 350px" :option="merchantInfoData.echartOptionLastWeek"
:autoresize="true" />
</div>
</el-card>
</div>
</div>
</el-card>
</div>
<div class="function mb-4">
<el-card class="flex-1 !border-none" shadow="never">
<template #header>
<span>常用功能</span>
</template>
<div class="flex flex-wrap">
<div
v-for="item in workbenchData.menu"
class="md:w-[12.5%] w-1/4 flex flex-col items-center"
:key="item"
>
<router-link :to="item.url" class="mb-3 flex flex-col items-center">
<image-contain width="40px" height="40px" :src="item?.image" />
<div class="mt-2">{{ item.name }}</div>
</router-link>
</div>
</div>
</el-card>
</div>
<div class="md:flex">
<el-card class="flex-1 !border-none md:mr-4 mb-4" shadow="never">
<template #header>
<span>本周商品销售数量</span>
</template>
<div>
<v-charts
style="height: 350px"
:option="merchantInfoData.echartOptionNowWeek"
:autoresize="true"
/>
</div>
</el-card>
</div>
<div class="md:flex">
<el-card class="flex-1 !border-none md:mr-4 mb-4" shadow="never">
<template #header>
<span>上周周商品销售数量</span>
</template>
<div>
<v-charts
style="height: 350px"
:option="merchantInfoData.echartOptionLastWeek"
:autoresize="true"
/>
</div>
</el-card>
</div>
</div>
</template>
<script lang="ts" setup name="workbench">
import { getWorkbench, merchantInfo } from '@/api/app'
import { orderBy } from 'lodash-es';
import vCharts from 'vue-echarts';
import { getCurrentInstance,type ComponentInternalInstance ,onMounted} from 'vue';
// bell
onMounted(()=>{
const {appContext} = getCurrentInstance()as ComponentInternalInstance;
appContext.config.globalProperties.$mitt.emit("selfEvent");
})
//
const merchantInfoData = ref({