feat: 动态路由&询盘首页
This commit is contained in:
parent
5546c9cb6f
commit
d452020044
@ -6,3 +6,27 @@ export const wechatPlatform = (platform) => {
|
||||
url: `/auth/wechatPlatform/${platform}`
|
||||
})
|
||||
}
|
||||
|
||||
export const sellerList = () => {
|
||||
return service({
|
||||
method: 'post',
|
||||
url: '/accessory/sellerlist/'
|
||||
})
|
||||
}
|
||||
|
||||
export const shopList = (ids) => {
|
||||
return service({
|
||||
method: 'post',
|
||||
url: '/accessory/shoplist',
|
||||
data: {
|
||||
ids
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const supplierList = () => {
|
||||
return service({
|
||||
method: 'post',
|
||||
url: `/member/supplierlist/`,
|
||||
})
|
||||
}
|
||||
|
33
src/api/inquiry.js
Normal file
33
src/api/inquiry.js
Normal file
@ -0,0 +1,33 @@
|
||||
import service from '@/service'
|
||||
|
||||
export const inquiryFilter = (users,status,days=7) => {
|
||||
return service({
|
||||
method: 'get',
|
||||
url: '/store/inquiryFilter',
|
||||
params: {
|
||||
users,
|
||||
status,
|
||||
days
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const inquiryList = (users,keys={},page=1,page_size=20) => {
|
||||
return service({
|
||||
method: 'post',
|
||||
url: '/store/inquiryList',
|
||||
data: {
|
||||
users,
|
||||
keys,
|
||||
page,
|
||||
page_size,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const customerList = () => {
|
||||
return service({
|
||||
method: 'get',
|
||||
url: '/store/customerList'
|
||||
})
|
||||
}
|
@ -36,3 +36,10 @@ export const getEmailCode = (email) => {
|
||||
url: `/accessory/mailVerifyCode?email=${email}`
|
||||
})
|
||||
}
|
||||
|
||||
export const loadShopInfo = () => {
|
||||
return service({
|
||||
method: 'get',
|
||||
url: '/store/loadShopInfo'
|
||||
})
|
||||
}
|
||||
|
@ -33,6 +33,12 @@
|
||||
active-text-color="#409EFF"
|
||||
router
|
||||
>
|
||||
<el-menu-item index="/home">
|
||||
<i class="fa fa-desktop"></i>
|
||||
<template #title>
|
||||
<span class="ml-2">我的工作台</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<template v-for="item in menuItems" :key="item.id">
|
||||
<!-- 无子菜单的菜单项 -->
|
||||
<el-menu-item v-if="!item.children" :index="item.id">
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createRouter,createWebHashHistory } from 'vue-router'
|
||||
import { getToken } from '@/utils'
|
||||
import { verifyToken } from '@/api/user'
|
||||
import { useUserStore } from '@/store'
|
||||
const modules = import.meta.glob("../views/**/**.vue")
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -27,10 +27,6 @@ const routes = [
|
||||
path:'/settings',
|
||||
name:'Settings',
|
||||
component: () => import('../views/Settings.vue')
|
||||
},{
|
||||
path:'/order',
|
||||
name:'Order',
|
||||
component: () => import('../views/order/index.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -41,12 +37,53 @@ const router = createRouter({
|
||||
routes
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const isLogin = getToken() ? true : false;
|
||||
const addDynamicRoutes = async (data) => {
|
||||
if (!data || !data.length) return;
|
||||
const homeRouters = routes.filter(v => v.path === '/main')[0];
|
||||
if (!homeRouters) return;
|
||||
homeRouters.children = [];
|
||||
homeRouters.children.push({
|
||||
path: '/home',
|
||||
name: 'Home',
|
||||
component: () => import('../views/Home.vue'),
|
||||
});
|
||||
homeRouters.children.push({
|
||||
path: '/settings',
|
||||
name: 'Settings',
|
||||
component: () => import('../views/Settings.vue'),
|
||||
});
|
||||
data.forEach(item => {
|
||||
homeRouters.children.push({
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
component: modules[`../views/${item.component}.vue`],
|
||||
})
|
||||
})
|
||||
homeRouters.children.push({
|
||||
path: '/:pathMatch(.*)',
|
||||
name: 'NotFound',
|
||||
component: () => import('../views/404.vue'),
|
||||
});
|
||||
return homeRouters;
|
||||
}
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if(to.path == '/login' || to.path == "/register" || to.path == "/wxlogin") {
|
||||
next()
|
||||
} else {
|
||||
isLogin ? next() : next('/')
|
||||
const userStore = useUserStore()
|
||||
if(userStore.isLoggedIn) {
|
||||
if(userStore.routeSetted) {
|
||||
next()
|
||||
} else {
|
||||
const homeRoutes = await addDynamicRoutes(userStore.routerList)
|
||||
router.addRoute(homeRoutes)
|
||||
userStore.routeSetted = true;
|
||||
next()
|
||||
}
|
||||
} else {
|
||||
next('/');
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,30 +1,261 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { loadShopInfo } from '../api/user'
|
||||
|
||||
const adminRoutes = [
|
||||
{
|
||||
path:'/inquiry-list',
|
||||
name:'InquiryList',
|
||||
component: 'inquiry/Index'
|
||||
},{
|
||||
path:'/customer-list',
|
||||
name:'CustomerList',
|
||||
component: 'customer/Index'
|
||||
},{
|
||||
path:'/order-list',
|
||||
name:'OrderList',
|
||||
component: 'order/index'
|
||||
},{
|
||||
path:'/product-list',
|
||||
name:'ProductList',
|
||||
component: 'product/Index'
|
||||
}
|
||||
]
|
||||
|
||||
const adminMenus = [
|
||||
{
|
||||
icon: 'fa fa-gavel',
|
||||
name: '询盘报价',
|
||||
id: 'inquiry',
|
||||
children: [
|
||||
{
|
||||
icon: 'fa fa-list',
|
||||
name: '询盘列表',
|
||||
path: '/inquiry-list'
|
||||
},{
|
||||
icon: 'fa fa-plus',
|
||||
name: '新增询价',
|
||||
path: '/inquiry-create'
|
||||
}
|
||||
]
|
||||
},{
|
||||
icon: 'fa fa-yen',
|
||||
name: '订单处理',
|
||||
id: 'order',
|
||||
children: [
|
||||
{
|
||||
icon: 'fa fa-list-alt',
|
||||
name: '报价列表',
|
||||
path: '/order-list'
|
||||
},{
|
||||
icon: 'fa fa-plus-square',
|
||||
name: '新增报价',
|
||||
path: '/order-create'
|
||||
}
|
||||
]
|
||||
},{
|
||||
icon: 'fa fa-cubes',
|
||||
name: '商品管理',
|
||||
id: 'product',
|
||||
children: [
|
||||
{
|
||||
icon: 'fa fa-list-alt',
|
||||
name: '商品列表',
|
||||
path: '/product-list'
|
||||
},{
|
||||
icon: 'fa fa-plus-square',
|
||||
name: '新增商品项',
|
||||
path: '/product-create'
|
||||
},{
|
||||
icon: 'fa fa-plus-square',
|
||||
name: '大件跟踪',
|
||||
path: '/product-tracking'
|
||||
},{
|
||||
icon: 'fa fa-plus-square',
|
||||
name: '更新件号',
|
||||
path: '/product-new-number'
|
||||
}
|
||||
]
|
||||
},{
|
||||
icon: 'fa fa-vcard',
|
||||
name: '客户关系',
|
||||
id: 'customer',
|
||||
children: [
|
||||
{
|
||||
icon: 'fa fa-list-alt',
|
||||
name: '客户关系',
|
||||
path: '/customer-list'
|
||||
},{
|
||||
icon: 'fa fa-plus-square',
|
||||
name: '供应商联系',
|
||||
path: '/supplier-list'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const managerRoutes = [
|
||||
{
|
||||
path:'/inquiry',
|
||||
name:'Inquiry',
|
||||
component: 'inquiry/index'
|
||||
},{
|
||||
path:'/customer',
|
||||
name:'Customer',
|
||||
component: 'customer/index'
|
||||
},{
|
||||
path:'/order',
|
||||
name:'Order',
|
||||
component: 'order/index'
|
||||
}
|
||||
]
|
||||
|
||||
const userRoutes = [
|
||||
{
|
||||
path:'/inquiry',
|
||||
name:'Inquiry',
|
||||
component: 'inquiry/index'
|
||||
},{
|
||||
path:'/customer',
|
||||
name:'Customer',
|
||||
component: 'customer/index'
|
||||
},{
|
||||
path:'/order',
|
||||
name:'Order',
|
||||
component: 'order/index'
|
||||
}
|
||||
]
|
||||
|
||||
export const useUserStore = defineStore('user-info',{
|
||||
state: () => {
|
||||
return {
|
||||
userInfo: {},
|
||||
authList: [],
|
||||
menuList: []
|
||||
shopInfo: {},
|
||||
routerList: [],
|
||||
menuList: [],
|
||||
user_groups: [],
|
||||
routeSetted: false,
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setInfo(userinfo) {
|
||||
async setInfo(userinfo) {
|
||||
this.userInfo = userinfo
|
||||
switch (userinfo.role) {
|
||||
case '0':
|
||||
this.routerList = adminRoutes
|
||||
break
|
||||
case '1':
|
||||
this.routerList = managerRoutes
|
||||
break
|
||||
case '2':
|
||||
this.routerList = userRoutes
|
||||
break
|
||||
}
|
||||
this.menuList = adminMenus
|
||||
const {data: res} = await loadShopInfo()
|
||||
if (res.error === 0) {
|
||||
this.shopInfo = res.data
|
||||
} else {
|
||||
this.shopInfo = {}
|
||||
}
|
||||
if(userinfo.role === '0') {
|
||||
this.userInfo.team = this.shopInfo.account.map(item => item.id)
|
||||
} else {
|
||||
this.userInfo.team = [userinfo.id]
|
||||
if(userinfo.authority && Object.keys(userinfo.authority).length > 0) {
|
||||
let authority = JSON.parse(userinfo.authority)
|
||||
if(authority.team && authority.team.length > 0) {
|
||||
this.userInfo.team = this.userInfo.team.concat(authority.team)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
clearInfo() {
|
||||
this.userInfo = {}
|
||||
this.user_groups = []
|
||||
this.shopInfo = {}
|
||||
this.routerList = []
|
||||
this.menuList = []
|
||||
this.routeSetted = false
|
||||
},
|
||||
logout() {
|
||||
this.userInfo = {}
|
||||
this.authList = []
|
||||
this.menuList = []
|
||||
this.clearInfo()
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
userId: (state) => {
|
||||
return state.userInfo.id || ''
|
||||
},
|
||||
isAdmin: (state) => {
|
||||
return state.userInfo.role === '0' || state.userInfo.role === '1'
|
||||
},
|
||||
isSalesman: (state) => {
|
||||
return state.userInfo.role !== '0' && state.userInfo.role !== '1'
|
||||
},
|
||||
isLoggedIn: (state) => {
|
||||
return Object.keys(state.userInfo).length > 0
|
||||
},
|
||||
hasRouterList: (state) => {
|
||||
return state.routerList.length > 0
|
||||
},
|
||||
team: (state) => {
|
||||
return state.userInfo.team
|
||||
},
|
||||
teamInfo: (state) => {
|
||||
let groups_info = {}
|
||||
state.userInfo.team.forEach(id => {
|
||||
let item = state.shopInfo.account.find(el => el.id === id)
|
||||
if(item) {
|
||||
groups_info[id] = {
|
||||
id: item.id,
|
||||
name: item.nickname || item.name,
|
||||
role: item.role
|
||||
}
|
||||
} else {
|
||||
groups_info[id] = {
|
||||
id: id,
|
||||
name: '未知用户',
|
||||
role: '2'
|
||||
}
|
||||
}
|
||||
})
|
||||
return groups_info
|
||||
}
|
||||
},
|
||||
persist: true
|
||||
})
|
||||
|
||||
export const useInquiryListStore = defineStore('inquiry-list',{
|
||||
state: () => {
|
||||
return {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
keys: {}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
reset() {
|
||||
this.currentPage = 1
|
||||
this.pageSize = 20
|
||||
this.keys = {}
|
||||
}
|
||||
},
|
||||
getters: {}
|
||||
})
|
||||
|
||||
export const useOrderListStore = defineStore('order-list',{
|
||||
state: () => {
|
||||
return {
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
keys: {}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
reset() {
|
||||
this.currentPage = 1
|
||||
this.pageSize = 20
|
||||
this.keys = {}
|
||||
}
|
||||
},
|
||||
getters: {}
|
||||
})
|
||||
|
30
src/views/404.vue
Normal file
30
src/views/404.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<el-empty description="无效的页面访问权限!">
|
||||
<template #description>
|
||||
<div class="w-full text-center mt-6">
|
||||
<span class="font-bold text-red-600 text-lg">
|
||||
你访问了一个无效的页面或没有权限访问该页面,请联系管理员处理。
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex justify-center items-center">
|
||||
<el-button type="info" @click="backToPrev" size="large"><i class="fa fa-arrow-left pr-2"></i>返回</el-button>
|
||||
<el-button type="primary" @click="backToHome" class="ml-6" size="large"><i class="fa fa-desktop pr-2"></i>工作台</el-button>
|
||||
</div>
|
||||
</el-empty>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
const backToHome = () => {
|
||||
router.push('/home')
|
||||
}
|
||||
|
||||
const backToPrev = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
@ -1,26 +1,131 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>首页</h2>
|
||||
<p>欢迎使用本系统</p>
|
||||
<p>当前时间:{{ new Date().toLocaleString() }}</p>
|
||||
<div class="mt-4">
|
||||
<el-button type="danger" @click="logout">注销退出</el-button>
|
||||
</div>
|
||||
<div class="w-full grid grid-cols-3 flex gap-4 p-4">
|
||||
<el-card shadow="hover" :style="{height: cardHeight + 'px'}">
|
||||
<template #header>
|
||||
<div class="flex items-center px-4 justify-between">
|
||||
<div class="font-bold text-lg">7日内待分派询盘单</div>
|
||||
<el-button type="primary" size="small" @click="getInquiryList">刷新</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
:data="allocating_inquiry"
|
||||
border
|
||||
:height="tableHeight"
|
||||
size="small"
|
||||
class="w-full pb-2"
|
||||
>
|
||||
<el-table-column type="index" label="#" width="40" header-align="center" align="center" :index="1"></el-table-column>
|
||||
<el-table-column prop="order_no" label="询单尾号" width="80" header-align="center" align="center">
|
||||
<template #default="{row}">
|
||||
<span>{{ row.order_no.slice(12) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="true_name" label="客户名称" width="120" header-align="center" show-overflow-tooltip>
|
||||
<template #default="{row}">
|
||||
<span>{{ row.true_name ? row.true_name : row.user_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="创建时间" width="160" header-align="center"></el-table-column>
|
||||
<el-table-column label="操作" header-align="center">
|
||||
<template #default="{row}">
|
||||
<div v-if="userStore.userInfo.role == '0' || userStore.userInfo.role == '1'" class="flex items-center justify-evenly">
|
||||
<el-button type="primary" size="small" @click="() => {}">派单</el-button>
|
||||
<el-button type="danger" size="small" @click="() => {}">丢弃</el-button>
|
||||
</div>
|
||||
<div v-else class="flex justify-center items-center">
|
||||
<el-button type="primary" size="small" @click="() => {}">抢单</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-card shadow="hover" :style="{height: cardHeight + 'px'}">
|
||||
<template #header>
|
||||
<div class="flex items-center px-4 justify-between">
|
||||
<div class="font-bold text-lg">7日内待完成询盘单</div>
|
||||
<el-button type="primary" size="small" @click="getProcessingInquiryList">刷新</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
:data="processing_inquiry"
|
||||
border
|
||||
:height="tableHeight"
|
||||
size="small"
|
||||
class="w-full pb-2"
|
||||
>
|
||||
<el-table-column type="index" label="#" width="40" header-align="center" align="center" :index="1"></el-table-column>
|
||||
<el-table-column prop="order_no" label="询单尾号" width="80" header-align="center" align="center">
|
||||
<template #default="{row}">
|
||||
<span>{{ row.order_no.slice(12) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="true_name" label="客户名称" width="120" header-align="center" show-overflow-tooltip>
|
||||
<template #default="{row}">
|
||||
<span>{{ row.true_name ? row.true_name : row.user_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="业务主办" width="80" header-align="center" align="center" show-overflow-tooltip v-if="userStore.isAdmin">
|
||||
<template #default="{row}">
|
||||
<span>{{ userStore.teamInfo[row.creator]?.name || '未知' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工作节点" width="80" header-align="center" align="center">
|
||||
<template #default="{row}">
|
||||
<span>{{ row.status == 0 ? '未开始' : row.status == 1 ? '待报价': row.status == 3 ? '已报价' : '其他' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="创建时间" width="160" header-align="center"></el-table-column>
|
||||
<el-table-column label="操作" header-align="center">
|
||||
<template #default="{row}">
|
||||
<div v-if="userStore.isAdmin" class="flex items-center justify-evenly">
|
||||
<el-button type="primary" size="small" @click="() => {}">处理</el-button>
|
||||
<el-button type="danger" size="small" @click="() => {}">结单</el-button>
|
||||
</div>
|
||||
<div v-else class="flex justify-center items-center">
|
||||
<el-button type="primary" size="small" @click="() => {}">结单</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref,onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/store'
|
||||
import { removeToken } from '@/utils'
|
||||
import { inquiryFilter } from '@/api/inquiry'
|
||||
|
||||
const cardHeight = ref(420)
|
||||
const tableHeight = ref(320)
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const logout = () => {
|
||||
userStore.clearInfo()
|
||||
removeToken()
|
||||
router.push('/login')
|
||||
const allocating_inquiry = ref([])
|
||||
const processing_inquiry = ref([])
|
||||
onMounted(async () => {
|
||||
await getInquiryList()
|
||||
await getProcessingInquiryList()
|
||||
})
|
||||
|
||||
const getInquiryList = async () => {
|
||||
const {data: res} = await inquiryFilter('0','start',7)
|
||||
if (res.error === 0) {
|
||||
allocating_inquiry.value = res.data
|
||||
} else {
|
||||
allocating_inquiry.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const getProcessingInquiryList = async () => {
|
||||
const {data: res} = await inquiryFilter(`${userStore.team.join(',')}`,'process',7)
|
||||
if (res.error === 0) {
|
||||
processing_inquiry.value = res.data
|
||||
} else {
|
||||
processing_inquiry.value = []
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<!-- 侧边菜单 -->
|
||||
<div class="sidebar" :class="{ 'collapsed': isCollapsed }" @mouseenter="expandMenu" @mouseleave="collapseMenu">
|
||||
<!-- 侧边面板 -->
|
||||
<SidePanel :is-collapsed="isCollapsed" :menu-items="menuItems" logo="jifuyun.cn.png" />
|
||||
<SidePanel :is-collapsed="isCollapsed" :menu-items="menuItems" :logo="logo" :title="title" />
|
||||
</div>
|
||||
|
||||
<div class="main-container">
|
||||
@ -34,50 +34,16 @@
|
||||
const isCollapsed = ref(true)
|
||||
|
||||
const isLoggedIn = computed(() => userStore.isLoggedIn)
|
||||
const logo = ref('jifuyun.cn.png')
|
||||
if(userStore.shopInfo && userStore.shopInfo.logo) {
|
||||
logo.value = 'https://www.jifuyun.cn/' + userStore.shopInfo.logo
|
||||
}
|
||||
const title = ref('机联云维')
|
||||
if(userStore.shopInfo && userStore.shopInfo.true_name) {
|
||||
title.value = userStore.shopInfo.true_name
|
||||
}
|
||||
// 菜单配置
|
||||
const menuItems = [
|
||||
{
|
||||
icon: 'fa fa-home',
|
||||
name: '首页概览',
|
||||
path: '/home',
|
||||
id: 'home'
|
||||
},{
|
||||
icon: 'fa fa-shopping-cart',
|
||||
name: '询价管理',
|
||||
id: 'inquiry',
|
||||
children: [
|
||||
{
|
||||
icon: 'fa fa-list',
|
||||
name: '询价列表',
|
||||
path: '/order'
|
||||
},{
|
||||
icon: 'fa fa-plus',
|
||||
name: '新增询价',
|
||||
path: '/inquiry/create'
|
||||
}
|
||||
]
|
||||
},{
|
||||
icon: 'fa fa-file-text',
|
||||
name: '报价管理',
|
||||
id: 'quote',
|
||||
children: [
|
||||
{
|
||||
icon: 'fa fa-list-alt',
|
||||
name: '报价列表',
|
||||
path: '/quote/list'
|
||||
},{
|
||||
icon: 'fa fa-plus-square',
|
||||
name: '新增报价',
|
||||
path: '/quote/create'
|
||||
}
|
||||
]
|
||||
},{
|
||||
icon: 'fa fa-cog',
|
||||
name: '系统设置',
|
||||
path: '/settings',
|
||||
id: 'settings',
|
||||
}
|
||||
]
|
||||
const menuItems = userStore.menuList || []
|
||||
|
||||
// 走马灯消息列表
|
||||
const newsList = [
|
||||
@ -97,7 +63,7 @@
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
userStore.$reset()
|
||||
userStore.logout()
|
||||
removeToken()
|
||||
router.push('/login')
|
||||
}
|
||||
|
@ -226,7 +226,7 @@
|
||||
router.push('/home')
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
user_store.clearInfo()
|
||||
user_store.logout()
|
||||
removeToken()
|
||||
}
|
||||
}
|
||||
|
28
src/views/customer/Index.vue
Normal file
28
src/views/customer/Index.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>客户首页</h2>
|
||||
<p>当前时间:{{ new Date().toLocaleString() }}</p>
|
||||
<div class="mt-4">
|
||||
<el-button type="danger" @click="logout">注销退出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/store'
|
||||
import { removeToken } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const logout = () => {
|
||||
userStore.logout()
|
||||
removeToken()
|
||||
router.push('/login')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
439
src/views/inquiry/Index.vue
Normal file
439
src/views/inquiry/Index.vue
Normal file
@ -0,0 +1,439 @@
|
||||
<template>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="6">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-select
|
||||
v-model="filterVariable.customer"
|
||||
placeholder="选择客户"
|
||||
size="large"
|
||||
multiple
|
||||
filterable
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
@change="startFilter"
|
||||
>
|
||||
<el-option v-for="customer in customer_list" :label="customer_name(customer)" :value="customer.id" :key="customer.id" />
|
||||
</el-select>
|
||||
<el-input v-model="filterVariable.code" placeholder="订单包含件号" size="large" @change="startFilter" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-select
|
||||
v-if="userStore.team.length > 1"
|
||||
v-model="filterVariable.operator"
|
||||
placeholder="选择业务员"
|
||||
size="large"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
@change="startFilter"
|
||||
>
|
||||
<el-option v-for="[id,item] of Object.entries(userStore.teamInfo)" :label="item.name" :value="id" :key="id" />
|
||||
</el-select>
|
||||
<el-select v-model="filterVariable.status" placeholder="订单状态" size="large" @change="startFilter">
|
||||
<el-option label="所有询盘单" :value="0"/>
|
||||
<el-option label="待处理" :value="1"/>
|
||||
<el-option label="已报价" :value="4"/>
|
||||
<el-option label="待付款" :value="6"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-date-picker
|
||||
v-model="filterVariable.date"
|
||||
type="daterange"
|
||||
unlink-panels
|
||||
range-separator="到"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="终到日期"
|
||||
size="large"
|
||||
value-format="YYYY-MM-DD"
|
||||
@change="startFilter"
|
||||
/>
|
||||
<el-button @click="resetFilter" type="success" class="hover:(bg-red-400 text-white)">重置筛选</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-table
|
||||
ref="orderTableRef"
|
||||
:data="order_list"
|
||||
:height="tableHeight"
|
||||
stripe
|
||||
fit
|
||||
style="width: 100%;"
|
||||
size="large"
|
||||
row-class-name="no-expand-icon"
|
||||
row-key="id"
|
||||
@row-click="expandPanel"
|
||||
@expand-change="expandChange"
|
||||
class="mt-2"
|
||||
>
|
||||
<!-- <el-table-column type="expand" width="0">
|
||||
<template #default="{row}">
|
||||
<div class="mt-2 p-2 flex justify-center overflow-auto">
|
||||
<el-table
|
||||
size="small"
|
||||
fit
|
||||
:data="row.offer"
|
||||
class="text-xs w-auto"
|
||||
style="border: 1px solid black;"
|
||||
:header-cell-style="{background: '#e0f2fe', color: 'black',borderColor: 'black'}"
|
||||
:cell-style="{borderColor: 'black'}"
|
||||
border
|
||||
>
|
||||
<el-table-column type="index" label="#" width="50" align="center" header-align="center"/>
|
||||
<el-table-column prop="brand_name" label="品牌" show-overflow-tooltip width="100" align="center" header-align="center"/>
|
||||
<el-table-column prop="code" label="件号" show-overflow-tooltip width="120" align="center" header-align="center"/>
|
||||
<el-table-column prop="name" label="品名" show-overflow-tooltip width="120" align="center" header-align="center"/>
|
||||
<el-table-column prop="market_price" label="面价" show-overflow-tooltip width="100" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ (Math.round(row.market_price * 100) / 100.00).toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="store" label="库存数" width="72" align="right" header-align="center"/>
|
||||
<el-table-column label="供应商采购" width="120" align="center" header-align="center">
|
||||
<el-table-column prop="selected" label="供应商" show-overflow-tooltip width="120" align="center" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ supplierName(row.selected) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报价" width="100" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ parseFloat(row.from[0]) ? parseFloat(row.from[0]).toFixed(2) : 0.00 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="急件价" width="100" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ row.from[3] && parseFloat(row.from[3]) ? parseFloat(row.from[3]).toFixed(2) : 0.00 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="可供数" width="60" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ row.from[1] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="货源" show-overflow-tooltip width="100" align="center" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ row.from[5] ? row.from[5] : '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" show-overflow-tooltip width="100" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ row.from[2] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="客户销售" header-align="center">
|
||||
<el-table-column prop="sell_price" label="售价" show-overflow-tooltip width="100" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ (Math.round(row.sell_price * 100) / 100.00).toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sell_price2" label="急件价" show-overflow-tooltip width="100" align="right" header-align="center">
|
||||
<template #default="{row}">
|
||||
{{ (Math.round(row.sell_price2 * 100) / 100.00).toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="amount" label="销售数" width="60" align="right" header-align="center"/>
|
||||
<el-table-column prop="note" label="备注" show-overflow-tooltip width="80" header-align="center"/>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column prop="order_no" label="订单号" header-align="center" align="center" width="200px">
|
||||
<template #default="{row}">
|
||||
<el-link type="primary" :underline="false" @click="router.push({path:'/pre-order/edit',query:{id:row.id}})"><el-text size="small" tag="b" class="hover:(bg-transparent text-red-900)">{{ row.order_no }}</el-text></el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="客户名称" :show-overflow-tooltip="true">
|
||||
<template #default="{row}">
|
||||
<el-text size="small">{{ row.true_name ? row.true_name : row.user_name }}</el-text>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="询盘状态" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag effect="dark" :type="row.status==0 ? 'danger' : row.status==5 ? 'success' : 'primary'" size="large" v-if="Object.keys(statusList).length">
|
||||
{{ row.status==0 ? (row.goods.length == 0 ? '添加商品' : (statusList[row.id][1] == 0 ? '制询价函' : (statusList[row.id][1] == statusList[row.id][2] ? '等待报价' : '等待回函'))) : orderStatus(row.status,row.is_del) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="询价状态" align="center">
|
||||
<template #default="{row}">
|
||||
<el-tag size="large" effect="dark" :type="inquiryShow(statusList[row.id][2],statusList[row.id][1])" v-if="Object.keys(statusList).length">
|
||||
{{ `${statusList[row.id][2]}/${statusList[row.id][1]}` }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="订单商品" align="center" header-align="center">
|
||||
<template #default="{row}">
|
||||
<el-popover effect="light" trigger="hover" placement="left-start" width="auto">
|
||||
<template #default>
|
||||
<el-table
|
||||
fit
|
||||
:data="goodsSorted(row.goods)"
|
||||
:height="240"
|
||||
style="width:320px"
|
||||
>
|
||||
<el-table-column prop="code" label="编码" :show-overflow-tooltip="true" width="100px"/>
|
||||
<el-table-column prop="b_name" label="品牌" :show-overflow-tooltip="true" width="80px" />
|
||||
<el-table-column prop="name" label="品名" :show-overflow-tooltip="true" width="80px" />
|
||||
<el-table-column prop="amount" label="数量" width="60px" />
|
||||
</el-table>
|
||||
</template>
|
||||
<template #reference>
|
||||
<el-tag color="#00828a" size="large" effect="dark" round>{{row.offer.length}}/{{row.goods.length}}</el-tag>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column label="询盘报价" align="right" header-align="center" prop="total_price">
|
||||
<template #default="{row}">
|
||||
<el-text :type="row.total_price==0?'danger':'primary'">{{`¥${row.total_price.toFixed(2)}`}}</el-text>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="note" label="订单备注" :show-overflow-tooltip="true" width="100px">
|
||||
<template #default="{row}">
|
||||
<el-text size="small" tag="b">{{ row.note }}</el-text>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="creator" label="业务主办" width="160px" :show-overflow-tooltip="true" header-align="center" align="center" v-if="userStore.team.length > 1">
|
||||
<template #default="{row}">
|
||||
{{ userStore.teamInfo[row.creator]?.name || `ID-${row.creator}` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="下单时间" width="200px"/>
|
||||
<el-table-column label="操作记录" header-align="center" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
size="default"
|
||||
type="default"
|
||||
@click="handleWorkflow(scope.row)"
|
||||
:icon="Share"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pages">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[20,30,40,50]"
|
||||
:disabled="false"
|
||||
size="small"
|
||||
:background="background"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@update:current-page="handleCurrentChange"
|
||||
@update:page-size="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
<!--
|
||||
<el-dialog
|
||||
v-model="workflowDialogVisible"
|
||||
title="订单工作流"
|
||||
width="30%"
|
||||
destroy-on-close
|
||||
center
|
||||
:draggable="true"
|
||||
>
|
||||
<div style="max-height: 50vh;overflow: auto;">
|
||||
<el-card class="box-card-edit">
|
||||
<el-timeline>
|
||||
<el-timeline-item
|
||||
v-for="(activity, index) in workflow"
|
||||
:key="index"
|
||||
:timestamp="activity.addtime"
|
||||
placement="top"
|
||||
>
|
||||
<el-card>
|
||||
<h4>{{ activity.action }}</h4>
|
||||
<p>{{ activity.user }}在{{ activity.addtime }}提交</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</el-card>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="workflowDialogVisible=false" :icon="Share">知道了!</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog> -->
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref,onMounted,computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
// import { orderFilter,orderCustomer,orderSeller,orderCreator,$orderStatus,getActionLog,supplierList,sellerList } from '@/api'
|
||||
// import { supplierList,sellerList } from '@/api'
|
||||
import { inquiryList,customerList } from '@/api/inquiry'
|
||||
// import { Edit,Share,Refresh } from '@element-plus/icons-vue'
|
||||
// import _ from 'lodash'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUserStore,useInquiryListStore } from '@/store'
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
const inquiryStore = useInquiryListStore()
|
||||
const { currentPage,pageSize,keys: filterVariable } = storeToRefs(inquiryStore)
|
||||
|
||||
const order_list = ref([])
|
||||
const total = ref(0)
|
||||
const orderTableRef = ref()
|
||||
const orderIds = ref([])
|
||||
const statusList = ref({})
|
||||
const customer_list = ref([])
|
||||
|
||||
const seller_list = ref([])
|
||||
const seller_list2 = ref([])
|
||||
const supplier_list = ref([])
|
||||
|
||||
const background = ref(false)
|
||||
const selectionRows = ref([])
|
||||
const workflowDialogVisible = ref(false)
|
||||
const tableHeight = ref(0)
|
||||
|
||||
onMounted(async () => {
|
||||
tableHeight.value = window.innerHeight - 180
|
||||
const { data:customer } = await customerList()
|
||||
if(customer.error == 0) {
|
||||
customer_list.value = customer.data
|
||||
}
|
||||
await get_order_list()
|
||||
// const {data:supplier} = await supplierList()
|
||||
// supplier_list.value = supplier.data.map(item => ({id:item.sid,name:item.sname,mobile:item.mobile}))
|
||||
// const {data:seller} = await sellerList()
|
||||
// seller_list2.value = seller.data.map(item => ({id:`G${item.id}`,name:`*商城*${item.seller_name}`,mobile:item.mobile}))
|
||||
})
|
||||
|
||||
const get_order_list = async () => {
|
||||
statusList.value = {}
|
||||
const { data:res } = await inquiryList(userStore.team.toString(),filterVariable.value,currentPage.value,pageSize.value)
|
||||
order_list.value = res.data
|
||||
total.value = res.total
|
||||
orderIds.value = []
|
||||
order_list.value.forEach(async (item) => {
|
||||
let total = 0
|
||||
item.offer.forEach(g => total += g.amount * parseFloat(g.sell_price))
|
||||
item['total_price'] = total
|
||||
orderIds.value.push(item.id)
|
||||
})
|
||||
// get_order_status()
|
||||
}
|
||||
|
||||
const get_order_status = async () => {
|
||||
let ids = order_list.value.map(item => item.id)
|
||||
const {data:status} = await $orderStatus(ids)
|
||||
statusList.value = status.data
|
||||
}
|
||||
|
||||
const workflow = ref([])
|
||||
const handleWorkflow = async (row) => {
|
||||
workflow.value = []
|
||||
const {data:res} = await getActionLog(row.id)
|
||||
workflow.value = res.data
|
||||
workflowDialogVisible.value = true
|
||||
}
|
||||
|
||||
const supplierName = computed(() => (id) => {
|
||||
if(`${id}`.startsWith('G')) {
|
||||
let ids = `${id}`.split('-')
|
||||
let idx = seller_list2.value.findIndex(item => item.id == ids[0])
|
||||
if(idx != -1) {
|
||||
return seller_list2.value[idx].name
|
||||
}
|
||||
} else {
|
||||
let idx = supplier_list.value.findIndex(item => item.id == id)
|
||||
if(idx != -1) {
|
||||
return supplier_list.value[idx].name
|
||||
}
|
||||
}
|
||||
return 'unknown'
|
||||
})
|
||||
|
||||
const customer_name = computed(() => (item) => {
|
||||
let val = `${item.true_name}`
|
||||
if(item.username != item.true_name) {
|
||||
val += ` ${item.username}`
|
||||
}
|
||||
if(item.mobile != null && item.mobile != '') {
|
||||
val += ` ${item.mobile}`
|
||||
}
|
||||
return val
|
||||
})
|
||||
|
||||
const expandPanel = (row) => {
|
||||
if(row.offer && row.offer.length > 0) {
|
||||
orderTableRef.value.toggleRowExpansion(row)
|
||||
}
|
||||
}
|
||||
|
||||
const expandRowKeys = ref([])
|
||||
const isExpanded = computed(() => (id) => expandRowKeys.value.findIndex(it => it == id))
|
||||
const expandChange = async (row,rows) => {
|
||||
expandRowKeys.value = rows.map(item => item.id)
|
||||
}
|
||||
|
||||
const startFilter = async () => {
|
||||
currentPage.value = 1
|
||||
await get_order_list()
|
||||
}
|
||||
|
||||
const resetFilter = async () => {
|
||||
inquiryStore.reset()
|
||||
await get_order_list()
|
||||
}
|
||||
|
||||
const handleSizeChange = async (val) => {
|
||||
currentPage.value = 1
|
||||
await get_order_list()
|
||||
}
|
||||
|
||||
const handleCurrentChange = async (val) => {
|
||||
await get_order_list()
|
||||
}
|
||||
|
||||
const orderStatus = computed(() => (status,isdel) => {
|
||||
status = parseInt(status)
|
||||
isdel = parseInt(isdel)
|
||||
if(isdel == 0) {
|
||||
return ['等待处理','已发询价','询价有回','已建报价','已发报价','待付款订单'][status]
|
||||
} else if(isdel == 1) {
|
||||
return '用户取消'
|
||||
} else {
|
||||
return '客服取消'
|
||||
}
|
||||
})
|
||||
|
||||
const goodsSorted = computed(() => (goods) => {
|
||||
return _.orderBy(goods, ['code', 'brand'], ['asc', 'asc'])
|
||||
})
|
||||
|
||||
const inquiryShow = computed(() => (val,total) => {
|
||||
if (val == 0 || val == '0') {
|
||||
return 'warning'
|
||||
} else if(total == val) {
|
||||
return 'success'
|
||||
} else {
|
||||
return 'primary'
|
||||
}
|
||||
})
|
||||
|
||||
const handleSelectionChange = (rows) => selectionRows.value = rows
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-table .cell {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.pages {
|
||||
padding-top: 20px;
|
||||
}
|
||||
:deep(.no-expand-icon .el-table__expand-icon) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
28
src/views/product/Index.vue
Normal file
28
src/views/product/Index.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>产品首页</h2>
|
||||
<p>当前时间:{{ new Date().toLocaleString() }}</p>
|
||||
<div class="mt-4">
|
||||
<el-button type="danger" @click="logout">注销退出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/store'
|
||||
import { removeToken } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const logout = () => {
|
||||
userStore.logout()
|
||||
removeToken()
|
||||
router.push('/login')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user