From 0181a84b01b1960931b712d5d7b7bdabe8bb1d2c Mon Sep 17 00:00:00 2001 From: weipengfei <2187978347@qq.com> Date: Sat, 25 May 2024 15:15:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 8 +- src/api/quote.ts | 23 ++ src/enums/pageEnum.ts | 1 + src/enums/requestEnums.ts | 1 + src/layout/default/index.vue | 55 +++- src/permission.ts | 16 +- src/router/routes.ts | 4 + src/stores/modules/user.ts | 9 +- src/utils/print.ts | 291 ++++++++++++++----- src/utils/request/index.ts | 236 ++++++++------- src/views/account/admin_login.vue | 131 +++++++++ src/views/account/login.vue | 3 +- src/views/data/merchant/audit/index.vue | 2 +- src/views/data/supplier/audit/index.vue | 2 +- src/views/data/supplier/supplier/index.vue | 157 +++++++--- src/views/goods/quote/detail.vue | 111 +++++++ src/views/goods/quote/edit.vue | 144 +++++++++ src/views/goods/quote/index.vue | 76 +++++ src/views/goods/quote/quoteOffer.vue | 244 ++++++++++++++++ src/views/opurchase/opurchaseclass/index.vue | 19 +- src/views/permission/admin/edit.vue | 4 +- src/views/translationOrder/index.vue | 2 +- 22 files changed, 1288 insertions(+), 251 deletions(-) create mode 100644 src/api/quote.ts create mode 100644 src/views/account/admin_login.vue create mode 100644 src/views/goods/quote/detail.vue create mode 100644 src/views/goods/quote/edit.vue create mode 100644 src/views/goods/quote/index.vue create mode 100644 src/views/goods/quote/quoteOffer.vue diff --git a/.env.development b/.env.development index 682dfda..cde91fe 100644 --- a/.env.development +++ b/.env.development @@ -3,8 +3,8 @@ VITE_NOW_TYPE = 'dist' # Base API # VITE_APP_BASE_URL='http://192.168.1.13:8546' -# VITE_PUSH_URL = 'ws://192.168.1.22:8787' -# VITE_APP_BASE_URL = 'http://192.168.1.22:8546' +VITE_PUSH_URL = 'ws://192.168.1.22:8787' +VITE_APP_BASE_URL = 'http://192.168.1.22:8546' -VITE_PUSH_URL ='wss://erp.lihaink.cn/pull' -VITE_APP_BASE_URL='https://erp.lihaink.cn' +# VITE_PUSH_URL ='wss://erp.lihaink.cn/pull' +# VITE_APP_BASE_URL='https://erp.lihaink.cn' diff --git a/src/api/quote.ts b/src/api/quote.ts new file mode 100644 index 0000000..9e6e26c --- /dev/null +++ b/src/api/quote.ts @@ -0,0 +1,23 @@ +import request from "@/utils/request"; + +/** + * @description 供应商报价日期列表 + */ +export function opurchaseGoodsOfferDateListsApi(params: any) { + return request.get({ url: "/operation/OpurchaseGoodsOffer/date_lists", params }); +} + +/** + * @description 供应商报价列表 + */ +export function opurchaseGoodsOfferListsApi(params: any) { + return request.get({ url: "/operation/OpurchaseGoodsOffer/lists", params }); +} + +/** + * @description 提交报价 + */ +export function opurchaseGoodsOfferOfferApi(params: any) { + return request.post({ url: "/operation/OpurchaseGoodsOffer/offer", params }); + +} diff --git a/src/enums/pageEnum.ts b/src/enums/pageEnum.ts index 1509ff5..f51a3b2 100644 --- a/src/enums/pageEnum.ts +++ b/src/enums/pageEnum.ts @@ -1,6 +1,7 @@ export enum PageEnum { //登录页面 LOGIN = '/login', + ADMIN_LOGIN = '/admin_login', //无权限页面 ERROR_403 = '/403', INDEX = '/' diff --git a/src/enums/requestEnums.ts b/src/enums/requestEnums.ts index 7ee2107..698a7e0 100644 --- a/src/enums/requestEnums.ts +++ b/src/enums/requestEnums.ts @@ -13,6 +13,7 @@ export enum RequestMethodsEnum { export enum RequestCodeEnum { SUCCESS = 1, FAIL = 0, + SERVER_ERROR = 500, LOGIN_FAILURE = -1, OPEN_NEW_PAGE = 2 } diff --git a/src/layout/default/index.vue b/src/layout/default/index.vue index c0fbf03..8dfa0a6 100644 --- a/src/layout/default/index.vue +++ b/src/layout/default/index.vue @@ -20,6 +20,7 @@ import LayoutMain from './components/main.vue' import LayoutSidebar from './components/sidebar/index.vue' import LayoutHeader from './components/header/index.vue' import { Push } from "@/common/push.js"; +import { print } from "@/utils/print"; const connection = new Push({ url: import.meta.env.VITE_PUSH_URL, // websocket地址 @@ -30,11 +31,63 @@ const connection = new Push({ const user_channel = connection.subscribe(`platform_1`); // const user_channel = connection.subscribe(`store_merchant_${1}`); +// setTimeout(()=>{ + +// print( +// { +// id: 405, +// merchant: 501, +// real_name: '阿哈', +// user_phone: '19330904744', +// user_address: '里海三楼', +// uid: '9', +// number: 'PF171617436315965155', +// total: '0.02', +// actual: '0.02', +// create_time: '2024-05-20 11:06:03', +// mer_name: '莲花农贸市场', +// mer_phone: '15566669999', +// mer_nickname: '小明', +// mer_user_mobile: '', +// nickname: '用户1532345', +// user_moblie: '19330904747', +// info: [ +// { +// goods: 317, +// nums: '1.00', +// price: '0.02', +// total: '0.02', +// unit_name: '斤', +// goods_name: '西瓜' +// }, +// { +// goods: 317, +// nums: '1.56', +// price: '1.98', +// total: '3.09', +// unit_name: '斤', +// goods_name: '苹果' +// }, +// { +// goods: 317, +// nums: '2.58', +// price: '3.68', +// total: '9.49', +// unit_name: '斤', +// goods_name: '香蕉' +// } +// ] +// } +// ) +// }, 1000) + // 当user-2频道有message事件的消息时 -user_channel.on('message', function (data) { +user_channel.on('message', function (data: any) { console.log("收到消息--",data); if(data.event=='platform_print'){ console.log('收到打印消息'); + if(typeof data.data != 'object' || !data.data?.info?.length) return ElMessage.error('收到订单,但打印数据不合法,请联系管理员'); + else print(data.data); } }); // 断线事件 diff --git a/src/permission.ts b/src/permission.ts index decf89b..f7101c4 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -12,20 +12,24 @@ import { PageEnum } from './enums/pageEnum' import useTabsStore from './stores/modules/multipleTabs' import { clearAuthInfo } from './utils/auth' import config from './config' +import cache from '@/utils/cache' // NProgress配置 NProgress.configure({ showSpinner: false }) const loginPath = PageEnum.LOGIN +const adminLoginPath = PageEnum.ADMIN_LOGIN const defaultPath = PageEnum.INDEX // 免登录白名单 -const whiteList: string[] = [PageEnum.LOGIN, PageEnum.ERROR_403] +const whiteList: string[] = [PageEnum.LOGIN, PageEnum.ERROR_403, PageEnum.ADMIN_LOGIN] router.beforeEach(async (to, from, next) => { // 开始 Progress Bar NProgress.start() document.title = to.meta.title ?? config.title const userStore = useUserStore() const tabsStore = useTabsStore() + const is_admin = cache.get('is_admin') + if (whiteList.includes(to.path)) { // 在免登录白名单,直接进入 next() @@ -33,7 +37,7 @@ router.beforeEach(async (to, from, next) => { // 获取用户信息 const hasGetUserInfo = Object.keys(userStore.userInfo).length !== 0 if (hasGetUserInfo) { - if (to.path === loginPath) { + if (to.path === loginPath || to.path === adminLoginPath) { next({ path: defaultPath }) } else { next() @@ -70,11 +74,15 @@ router.beforeEach(async (to, from, next) => { next({ ...to, replace: true }) } catch (err) { clearAuthInfo() - next({ path: loginPath, query: { redirect: to.fullPath } }) + if (is_admin==1) { + next({ path: adminLoginPath, query: { redirect: to.fullPath } }) + } else next({ path: loginPath, query: { redirect: to.fullPath } }) } } } else { - next({ path: loginPath, query: { redirect: to.fullPath } }) + if (is_admin==1) { + next({ path: adminLoginPath, query: { redirect: to.fullPath } }) + } else next({ path: loginPath, query: { redirect: to.fullPath } }) } }) diff --git a/src/router/routes.ts b/src/router/routes.ts index a3603cb..f727d0e 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -34,6 +34,10 @@ export const constantRoutes: Array<RouteRecordRaw> = [ path: PageEnum.LOGIN, component: () => import('@/views/account/login.vue') }, + { + path: PageEnum.ADMIN_LOGIN, + component: () => import('@/views/account/admin_login.vue') + }, { path: '/user', component: LAYOUT, diff --git a/src/stores/modules/user.ts b/src/stores/modules/user.ts index 27b4ebc..d10e5e2 100644 --- a/src/stores/modules/user.ts +++ b/src/stores/modules/user.ts @@ -32,15 +32,17 @@ const useUserStore = defineStore({ this.perms = [] }, login(playload: any) { - const { account, password } = playload + const { account, password, is_admin } = playload return new Promise((resolve, reject) => { login({ account: account.trim(), - password: password + password: password, + is_admin: is_admin }) .then((data) => { this.token = data.token cache.set(TOKEN_KEY, data.token) + cache.set('is_admin', is_admin) resolve(data) }) .catch((error) => { @@ -53,7 +55,8 @@ const useUserStore = defineStore({ logout() .then(async (data) => { this.token = '' - await router.push(PageEnum.LOGIN) + const is_admin = cache.get('is_admin') + await router.push(is_admin==1 ? PageEnum.ADMIN_LOGIN : PageEnum.LOGIN) clearAuthInfo() resolve(data) }) diff --git a/src/utils/print.ts b/src/utils/print.ts index 550ca85..51f2b40 100644 --- a/src/utils/print.ts +++ b/src/utils/print.ts @@ -16,50 +16,188 @@ export const print = (data: any) => { const list = hiprint.hiwebSocket.getPrinterList(); console.log(list); + let nowHeight = 0; + let textHeight = 10; + // 下列方法都是没有拖拽设计页面的, 相当于代码模式, 使用代码设计页面 // 想要实现拖拽设计页面,请往下看 '自定义设计' var hiprintTemplate = new hiprint.PrintTemplate(); + // 纸张高度 固定为 130 pt + 商品数量高度 + let oneHeight = 120 + Math.ceil((data.info.length * 2 * 10) / 2.84); + // 模板宽度单位是mm ( 1mm ~= 2.84pt ) 其他的宽高单位是pt var panel = hiprintTemplate.addPrintPanel({ - width: WIDTH, // 58mm = 164pt - height: 58, + width: 58, // 58mm = 164pt + height: oneHeight, paperNumberDisabled: true, - topOffset: -1, }); - //文本 - panel.addPrintText({ - options: { + let options = (e: any) => { + nowHeight += textHeight; + let opt = { width: T_WIDTH, - height: 10, - top: 10, + height: textHeight, + top: nowHeight, left: T_LEFT, - title: "hiprint插件手动添加text", + title: "", + }; + if (typeof e === "string") opt.title = e; + else opt = Object.assign(opt, e); + return { + options: opt, + }; + }; + + let lineTitle = () => { + nowHeight += textHeight; + let left = Math.floor(T_WIDTH / 3); + panel.addPrintText({ + options: { + width: left, + height: 10, + top: nowHeight, + left: 0, + title: "单价", + textAlign: "center", + }, + }); + panel.addPrintText({ + options: { + width: left, + height: textHeight, + top: nowHeight, + left: left, + title: "数量", + textAlign: "center", + }, + }); + panel.addPrintText({ + options: { + width: left, + height: textHeight, + top: nowHeight, + left: left * 2, + title: "小计", + textAlign: "center", + }, + }); + }; + + let lineOptions = (text1: any, text2: any, text3: any) => { + nowHeight += textHeight; + let left = Math.floor(T_WIDTH / 3); + panel.addPrintText({ + options: { + width: left, + height: 10, + top: nowHeight, + left: 0, + title: text1 + "", + textAlign: "center", + }, + }); + panel.addPrintText({ + options: { + width: left, + height: textHeight, + top: nowHeight, + left: left, + title: text2 + "", + textAlign: "center", + }, + }); + panel.addPrintText({ + options: { + width: left, + height: textHeight, + top: nowHeight, + left: left * 2, + title: text3 + "", + textAlign: "center", + }, + }); + }; + + //文本 *1 + panel.addPrintText( + options({ + title: "泸优采-采购单", textAlign: "center", - }, + }) + ); + + //文本 *6 + panel.addPrintText(options("单号: " + data.number)); + panel.addPrintText(options("配送时间: " + data.create_time)); + panel.addPrintText(options("配送员: " + data.mer_nickname)); + panel.addPrintText(options("配送电话: " + data.mer_phone)); + panel.addPrintText(options("======================")); + panel.addPrintText(options("商品信息: ")); + + //格式化 *1 + x * y + lineTitle(); + data.info.forEach((item: any) => { + panel.addPrintText(options(item.goods_name)); + if(item.nums==Math.floor(+item.nums)) item.nums = Number(item.nums).toFixed(0); + lineOptions( + `${item.price}元`, + `${item.nums}${item.unit_name}`, + `${item.total}元` + ); }); - //长文本 - panel.addPrintLongText({ + + //文本 *5 + panel.addPrintText(options("======================")); + panel.addPrintText(options(`合计: ${data.total}元`)); + panel.addPrintText(options("提货点: " + data.mer_name)); + panel.addPrintText(options("提货点电话: " + data.mer_phone)); + panel.addPrintText(options("提货点负责人签字:")); + // https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png //无字 + // https://lihai001.oss-cn-chengdu.aliyuncs.com/def/54705202405221504133485.png //有字 + // panel.addPrintRect({ options: { width: T_WIDTH, height:30,top: nowHeight + 15, left: T_LEFT,borderColor:'',borderWidth:0.75 } }); + // nowHeight+=40; + + // 文本 *6 + panel.addPrintImage({ options: { width: T_WIDTH, - height: 35, - top: 30, + height: 50, + top: nowHeight + 15, left: T_LEFT, - title: "长文本:hiprint是一个很好的webjs打印,浏览器在的地方他都可以运行", + title: "", + src: "https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png", }, }); - //长文本 - panel.addPrintLongText({ + nowHeight += 60; + // 文本 *4 + panel.addPrintText(options("收货人: " + data.real_name)); + panel.addPrintText(options("收货地址: " + data.user_address)); + panel.addPrintText(options("联系电话: " + data.user_phone)); + panel.addPrintText(options("收货人签字:")); + // panel.addPrintRect({ options: { width: T_WIDTH, height:30,top: nowHeight+15, left: T_LEFT,borderColor:'',borderWidth:0.75 } }); + + // 文本 *6 + panel.addPrintImage({ options: { width: T_WIDTH, - height: 35, - top: 80, + height: 50, + top: nowHeight + 15, left: T_LEFT, - title: - "长文本:直接打印,需要安装客户端, 直接打印,需要安装客户端, 直接打印,需要安装客户端, 直接打印,需要安装客户端", + title: "", + src: "https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png", }, }); + nowHeight += 60; + + // 文本 *4 + panel.addPrintText(options("")); + panel.addPrintText(options("")); + panel.addPrintText(options("")); + panel.addPrintText(options("======================")); + + // 合计高度 23 + length * 2 + //打印 hiprintTemplate.print({}); //直接打印,需要安装客户端 @@ -94,25 +232,25 @@ export const testPrint = () => { paperNumberDisabled: true, }); - let options = (e: any)=>{ - nowHeight+=textHeight; + let options = (e: any) => { + nowHeight += textHeight; let opt = { width: T_WIDTH, height: textHeight, top: nowHeight, left: T_LEFT, - title: '', - } - if(typeof e === 'string') opt.title = e; + title: "", + }; + if (typeof e === "string") opt.title = e; else opt = Object.assign(opt, e); return { - options: opt - } - } + options: opt, + }; + }; - let lineTitle = ()=>{ - nowHeight+=textHeight; - let left = Math.floor(T_WIDTH/3) ; + let lineTitle = () => { + nowHeight += textHeight; + let left = Math.floor(T_WIDTH / 3); panel.addPrintText({ options: { width: left, @@ -143,18 +281,18 @@ export const testPrint = () => { textAlign: "center", }, }); - } + }; - let lineOptions = (text1: any, text2: any, text3: any)=>{ - nowHeight+=textHeight; - let left = Math.floor(T_WIDTH/3) ; + let lineOptions = (text1: any, text2: any, text3: any) => { + nowHeight += textHeight; + let left = Math.floor(T_WIDTH / 3); panel.addPrintText({ options: { width: left, height: 10, top: nowHeight, left: 0, - title: text1+"", + title: text1 + "", textAlign: "center", }, }); @@ -164,7 +302,7 @@ export const testPrint = () => { height: textHeight, top: nowHeight, left: left, - title: text2+"", + title: text2 + "", textAlign: "center", }, }); @@ -174,17 +312,19 @@ export const testPrint = () => { height: textHeight, top: nowHeight, left: left * 2, - title: text3+"", + title: text3 + "", textAlign: "center", }, }); - } + }; //文本 *1 - panel.addPrintText(options({ - title: '泸优采-小票0', - textAlign: "center", - })); + panel.addPrintText( + options({ + title: "泸优采-小票0", + textAlign: "center", + }) + ); //文本 *6 panel.addPrintText(options("单号: PF171617436315965155")); @@ -205,11 +345,11 @@ export const testPrint = () => { //文本 *13 panel.addPrintText(options("======================")); - panel.addPrintText(options('合计: 0.75元')); - - panel.addPrintText(options('提货点: 莲花农贸市场')); - panel.addPrintText(options('提货点电话: 19330904744')); - panel.addPrintText(options('提货点负责人签字:')); + panel.addPrintText(options("合计: 0.75元")); + + panel.addPrintText(options("提货点: 莲花农贸市场")); + panel.addPrintText(options("提货点电话: 19330904744")); + panel.addPrintText(options("提货点负责人签字:")); // https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png //无字 // https://lihai001.oss-cn-chengdu.aliyuncs.com/def/54705202405221504133485.png //有字 // panel.addPrintRect({ options: { width: T_WIDTH, height:30,top: nowHeight + 15, left: T_LEFT,borderColor:'',borderWidth:0.75 } }); @@ -217,38 +357,37 @@ export const testPrint = () => { panel.addPrintImage({ options: { width: T_WIDTH, - height:50, - top: nowHeight + 15, - left: T_LEFT, - title: '', - src: 'https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png' - } - }) - nowHeight+=60; - panel.addPrintText(options('收货人: 阿哈')); - panel.addPrintText(options('收货地址: 里海科技')); - panel.addPrintText(options('联系电话: 17685151643')); - panel.addPrintText(options('收货人签字:')); + height: 50, + top: nowHeight + 15, + left: T_LEFT, + title: "", + src: "https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png", + }, + }); + nowHeight += 60; + panel.addPrintText(options("收货人: 阿哈")); + panel.addPrintText(options("收货地址: 里海科技")); + panel.addPrintText(options("联系电话: 17685151643")); + panel.addPrintText(options("收货人签字:")); // panel.addPrintRect({ options: { width: T_WIDTH, height:30,top: nowHeight+15, left: T_LEFT,borderColor:'',borderWidth:0.75 } }); panel.addPrintImage({ options: { width: T_WIDTH, height: 50, - top: nowHeight + 15, - left: T_LEFT, - title: '', - src: 'https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png' - } - }) - nowHeight+=60; + top: nowHeight + 15, + left: T_LEFT, + title: "", + src: "https://lihai001.oss-cn-chengdu.aliyuncs.com/def/db264202405221455038529.png", + }, + }); + nowHeight += 60; panel.addPrintText(options("")); panel.addPrintText(options("")); panel.addPrintText(options("")); panel.addPrintText(options("======================")); - // 合计高度 23 + length * 2 - + // 合计高度 23 + length * 2 //打印 // hiprintTemplate.print({}); @@ -258,22 +397,24 @@ export const testPrint = () => { // 发送任务到打印机成功 hiprintTemplate.on("printSuccess", (e: any) => { console.log("printSuccess", e); + ElMessage.success('订单已加入打印队列'); }); // 发送任务到打印机失败 hiprintTemplate.on("printError", (e: any) => { console.log("printError", e); + ElMessage.error('打印失败,请检查是否正确连接打印机!'); }); }; -export const printerList = ()=>{ - try{ +export const printerList = () => { + try { const list = hiprint.hiwebSocket.getPrinterList(); return list; - }catch{ - ElMessage.error("请先安装打印机客户端") + } catch { + ElMessage.error("请先安装打印机客户端"); return []; } -} +}; // 计算字符串长度 function calculateStringLength(str: string) { diff --git a/src/utils/request/index.ts b/src/utils/request/index.ts index e66915d..6c5f649 100644 --- a/src/utils/request/index.ts +++ b/src/utils/request/index.ts @@ -1,123 +1,133 @@ -import { merge } from 'lodash' -import configs from '@/config' -import { Axios } from './axios' -import { ContentTypeEnum, RequestCodeEnum, RequestMethodsEnum } from '@/enums/requestEnums' -import type { AxiosHooks } from './type' -import { clearAuthInfo, getToken } from '../auth' -import feedback from '../feedback' -import NProgress from 'nprogress' -import { AxiosError, type AxiosRequestConfig } from 'axios' -import router from '@/router' -import { PageEnum } from '@/enums/pageEnum' +import { merge } from "lodash"; +import configs from "@/config"; +import { Axios } from "./axios"; +import { + ContentTypeEnum, + RequestCodeEnum, + RequestMethodsEnum, +} from "@/enums/requestEnums"; +import type { AxiosHooks } from "./type"; +import { clearAuthInfo, getToken } from "../auth"; +import feedback from "../feedback"; +import NProgress from "nprogress"; +import { AxiosError, type AxiosRequestConfig } from "axios"; +import router from "@/router"; +import { PageEnum } from "@/enums/pageEnum"; // 处理axios的钩子函数 const axiosHooks: AxiosHooks = { - requestInterceptorsHook(config) { - NProgress.start() - const { withToken, isParamsToData } = config.requestOptions - const params = config.params || {} - const headers = config.headers || {} + requestInterceptorsHook(config) { + NProgress.start(); + const { withToken, isParamsToData } = config.requestOptions; + const params = config.params || {}; + const headers = config.headers || {}; - // 添加token - if (withToken) { - const token = getToken() - headers.token = token - } - // POST请求下如果无data,则将params视为data - if ( - isParamsToData && - !Reflect.has(config, 'data') && - config.method?.toUpperCase() === RequestMethodsEnum.POST - ) { - config.data = params - config.params = {} - } - config.headers = headers - return config - }, - requestInterceptorsCatchHook(err) { - NProgress.done() - return err - }, - async responseInterceptorsHook(response) { - NProgress.done() - const { isTransformResponse, isReturnDefaultResponse } = response.config.requestOptions - - //返回默认响应,当需要获取响应头及其他数据时可使用 - if (isReturnDefaultResponse) { - return response - } - // 是否需要对数据进行处理 - if (!isTransformResponse) { - return response.data - } - const { code, data, show, msg } = response.data - switch (code) { - case RequestCodeEnum.SUCCESS: - if (show) { - msg && feedback.msgSuccess(msg) - } - return data - case RequestCodeEnum.FAIL: - if (show) { - msg && feedback.msgError(msg) - } - return Promise.reject(data) - case RequestCodeEnum.LOGIN_FAILURE: - clearAuthInfo() - router.push(PageEnum.LOGIN) - return Promise.reject() - case RequestCodeEnum.OPEN_NEW_PAGE: - window.location.href = data.url - return data - default: - return data - } - }, - responseInterceptorsCatchHook(error) { - NProgress.done() - if (error.code !== AxiosError.ERR_CANCELED) { - error.message && feedback.msgError(error.message) - } - return Promise.reject(error) + // 添加token + if (withToken) { + const token = getToken(); + headers.token = token; } -} + // POST请求下如果无data,则将params视为data + if ( + isParamsToData && + !Reflect.has(config, "data") && + config.method?.toUpperCase() === RequestMethodsEnum.POST + ) { + config.data = params; + config.params = {}; + } + config.headers = headers; + return config; + }, + requestInterceptorsCatchHook(err) { + NProgress.done(); + return err; + }, + async responseInterceptorsHook(response) { + NProgress.done(); + const { isTransformResponse, isReturnDefaultResponse } = + response.config.requestOptions; + + //返回默认响应,当需要获取响应头及其他数据时可使用 + if (isReturnDefaultResponse) { + return response; + } + // 是否需要对数据进行处理 + if (!isTransformResponse) { + return response.data; + } + const { code, data, show, msg } = response.data; + switch (code) { + case RequestCodeEnum.SUCCESS: + if (show) { + msg && feedback.msgSuccess(msg); + } + return data; + case RequestCodeEnum.FAIL: + if (show) { + msg && feedback.msgError(msg); + } + return Promise.reject(data); + case RequestCodeEnum.SERVER_ERROR: + if (show) { + msg && feedback.msgError(msg); + } + return Promise.reject(data); + case RequestCodeEnum.LOGIN_FAILURE: + clearAuthInfo(); + router.push(PageEnum.LOGIN); + return Promise.reject(); + case RequestCodeEnum.OPEN_NEW_PAGE: + window.location.href = data.url; + return data; + default: + return data; + } + }, + responseInterceptorsCatchHook(error) { + NProgress.done(); + if (error.code !== AxiosError.ERR_CANCELED) { + error.message && feedback.msgError(error.message); + } + return Promise.reject(error); + }, +}; const defaultOptions: AxiosRequestConfig = { - //接口超时时间 - timeout: configs.timeout, - // 基础接口地址 - baseURL: configs.baseUrl, - //请求头 - headers: { 'Content-Type': ContentTypeEnum.JSON, version: configs.version }, - // 处理 axios的钩子函数 - axiosHooks: axiosHooks, - // 每个接口可以单独配置 - requestOptions: { - // 是否将params视为data参数,仅限post请求 - isParamsToData: true, - //是否返回默认的响应 - isReturnDefaultResponse: false, - // 需要对返回数据进行处理 - isTransformResponse: true, - // 接口拼接地址 - urlPrefix: configs.urlPrefix, - // 忽略重复请求 - ignoreCancelToken: false, - // 是否携带token - withToken: true, - // 开启请求超时重新发起请求请求机制 - isOpenRetry: true, - // 重新请求次数 - retryCount: 2 - } -} + //接口超时时间 + timeout: configs.timeout, + // 基础接口地址 + baseURL: configs.baseUrl, + //请求头 + headers: { "Content-Type": ContentTypeEnum.JSON, version: configs.version }, + // 处理 axios的钩子函数 + axiosHooks: axiosHooks, + // 每个接口可以单独配置 + requestOptions: { + // 是否将params视为data参数,仅限post请求 + isParamsToData: true, + //是否返回默认的响应 + isReturnDefaultResponse: false, + // 需要对返回数据进行处理 + isTransformResponse: true, + // 接口拼接地址 + urlPrefix: configs.urlPrefix, + // 忽略重复请求 + ignoreCancelToken: false, + // 是否携带token + withToken: true, + // 开启请求超时重新发起请求请求机制 + isOpenRetry: true, + // 重新请求次数 + retryCount: 2, + }, +}; function createAxios(opt?: Partial<AxiosRequestConfig>) { - return new Axios( - // 深度合并 - merge(defaultOptions, opt || {}) - ) + return new Axios( + // 深度合并 + merge(defaultOptions, opt || {}) + ); } -const request = createAxios() -export default request +const request = createAxios(); +export default request; diff --git a/src/views/account/admin_login.vue b/src/views/account/admin_login.vue new file mode 100644 index 0000000..5c33fba --- /dev/null +++ b/src/views/account/admin_login.vue @@ -0,0 +1,131 @@ +<template> + <div class="login flex flex-col"> + <div class="flex-1 flex items-center justify-center"> + <div class="login-card flex rounded-md"> + <div class="flex-1 h-full hidden md:inline-block"> + <image-contain :src="config.login_image" :width="400" height="100%" /> + </div> + <div + class="login-form bg-body flex flex-col justify-center px-10 py-10 md:w-[400px] w-[375px] flex-none mx-auto" + > + <div class="text-center text-3xl font-medium mb-8">{{ '里海ERP后台管理系统' || config.web_name }}</div> + <el-form ref="formRef" :model="formData" size="large" :rules="rules"> + <el-form-item prop="account"> + <el-input + v-model="formData.account" + placeholder="请输入账号" + @keyup.enter="handleEnter" + > + <template #prepend> + <icon name="el-icon-User" /> + </template> + </el-input> + </el-form-item> + <el-form-item prop="password"> + <el-input + ref="passwordRef" + v-model="formData.password" + show-password + placeholder="请输入密码" + @keyup.enter="handleLogin" + > + <template #prepend> + <icon name="el-icon-Lock" /> + </template> + </el-input> + </el-form-item> + </el-form> + <div class="mb-5"> + <el-checkbox v-model="remAccount" label="记住账号"></el-checkbox> + </div> + <el-button type="primary" size="large" :loading="isLock" @click="lockLogin"> + 登录 + </el-button> + </div> + </div> + </div> + <layout-footer /> + </div> +</template> + +<script lang="ts" setup> +import { computed, onMounted, reactive, ref, shallowRef } from 'vue' +import type { InputInstance, FormInstance } from 'element-plus' +import LayoutFooter from '@/layout/components/footer.vue' +import useAppStore from '@/stores/modules/app' +import useUserStore from '@/stores/modules/user' +import cache from '@/utils/cache' +import { ACCOUNT_KEY } from '@/enums/cacheEnums' +import { PageEnum } from '@/enums/pageEnum' +import { useLockFn } from '@/hooks/useLockFn' +const passwordRef = shallowRef<InputInstance>() +const formRef = shallowRef<FormInstance>() +const appStore = useAppStore() +const userStore = useUserStore() +const route = useRoute() +const router = useRouter() +const remAccount = ref(false) +const config = computed(() => appStore.config) +const formData = reactive({ + account: '', + password: '', + is_admin: 1 //1管理员, 0是供应链 +}) +const rules = { + account: [ + { + required: true, + message: '请输入账号', + trigger: ['blur'] + } + ], + password: [ + { + required: true, + message: '请输入密码', + trigger: ['blur'] + } + ] +} +// 回车按键监听 +const handleEnter = () => { + if (!formData.password) { + return passwordRef.value?.focus() + } + handleLogin() +} +// 登录处理 +const handleLogin = async () => { + await formRef.value?.validate() + // 记住账号,缓存 + cache.set(ACCOUNT_KEY, { + remember: remAccount.value, + account: remAccount.value ? formData.account : '' + }) + await userStore.login(formData) + const { + query: { redirect } + } = route + const path = typeof redirect === 'string' ? redirect : PageEnum.INDEX + router.push(path) +} +const { isLock, lockFn: lockLogin } = useLockFn(handleLogin) + +onMounted(() => { + const value = cache.get(ACCOUNT_KEY) + if (value?.remember) { + remAccount.value = value.remember + formData.account = value.account + } +}) +</script> + +<style lang="scss" scoped> +.login { + background-image: url('./images/login_bg.png'); + @apply min-h-screen bg-no-repeat bg-center bg-cover; + .login-card { + height: 400px; + } +} +</style> diff --git a/src/views/account/login.vue b/src/views/account/login.vue index 74b1aeb..ddc1837 100644 --- a/src/views/account/login.vue +++ b/src/views/account/login.vue @@ -68,7 +68,8 @@ const remAccount = ref(false) const config = computed(() => appStore.config) const formData = reactive({ account: '', - password: '' + password: '', + is_admin: 0 //1管理员, 0是供应链 }) const rules = { account: [ diff --git a/src/views/data/merchant/audit/index.vue b/src/views/data/merchant/audit/index.vue index 31c7f8e..22dce02 100644 --- a/src/views/data/merchant/audit/index.vue +++ b/src/views/data/merchant/audit/index.vue @@ -281,7 +281,7 @@ 审核 </el-button> <el-button - v-else-if="!row.status" + v-else-if="!row.status && !row.mark" link type="warning" @click="handleDetail(row)" diff --git a/src/views/data/supplier/audit/index.vue b/src/views/data/supplier/audit/index.vue index 3d8925a..ad92872 100644 --- a/src/views/data/supplier/audit/index.vue +++ b/src/views/data/supplier/audit/index.vue @@ -56,7 +56,7 @@ <el-button v-if="!row.status && (row.mark=='' || row.mark==null)" link type="primary" @click="handleDetail(row)"> 审核 </el-button> - <el-button v-else-if="!row.status" link type="warning" @click="handleDetail(row)"> + <el-button v-else-if="!row.status && !row.mark" link type="warning" @click="handleDetail(row)"> 重新审核 </el-button> </template> diff --git a/src/views/data/supplier/supplier/index.vue b/src/views/data/supplier/supplier/index.vue index 884c62e..40363ea 100644 --- a/src/views/data/supplier/supplier/index.vue +++ b/src/views/data/supplier/supplier/index.vue @@ -5,23 +5,43 @@ <el-row> <el-col :span="6"> <el-form-item label="供应商分类" prop="category_id"> - <el-select v-model="queryParams.category_id" clearable placeholder="请选择供应商类型"> - <el-option v-for="(item, index) in dictData.mer_category_type" :key="index" :label="item.name" - :value="parseInt(item.value)" /> + <el-select + v-model="queryParams.category_id" + clearable + placeholder="请选择供应商类型" + > + <el-option + v-for="(item, index) in dictData.mer_category_type" + :key="index" + :label="item.name" + :value="parseInt(item.value)" + /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="供应商类型" prop="type_id"> - <el-select v-model="queryParams.type_id" clearable placeholder="请选择供应商类型"> - <el-option v-for="(item, index) in dictData.merchat_type" :key="index" :label="item.name" - :value="parseInt(item.value)" /> + <el-select + v-model="queryParams.type_id" + clearable + placeholder="请选择供应商类型" + > + <el-option + v-for="(item, index) in dictData.merchat_type" + :key="index" + :label="item.name" + :value="parseInt(item.value)" + /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="供应商名称" prop="mer_name"> - <el-input v-model="queryParams.mer_name" clearable placeholder="请输入供应商名称" /> + <el-input + v-model="queryParams.mer_name" + clearable + placeholder="请输入供应商名称" + /> </el-form-item> </el-col> <el-col :span="6"> @@ -34,13 +54,21 @@ </el-form> </el-card> <el-card class="!border-none" v-loading="pager.loading" shadow="never"> - <el-button v-perms="['supplier.supplier/add']" type="primary" @click="handleAdd"> + <el-button + v-perms="['supplier.supplier/add']" + type="primary" + @click="handleAdd" + > <template #icon> <icon name="el-icon-Plus" /> </template> 新增 </el-button> - <el-button v-perms="['supplier.supplier/delete']" :disabled="!selectData.length" @click="handleDelete(selectData)"> + <el-button + v-perms="['supplier.supplier/delete']" + :disabled="!selectData.length" + @click="handleDelete(selectData)" + > 删除 </el-button> <div class="mt-4"> @@ -59,14 +87,33 @@ /> </template> </el-table-column> --> - <el-table-column label="供应商类型" prop="type_id" show-overflow-tooltip> + <el-table-column + label="供应商类型" + prop="type_id" + show-overflow-tooltip + > <template #default="{ row }"> - <dict-value :options="dictData.merchat_type" :value="row.type_id" /> + <dict-value + :options="dictData.merchat_type" + :value="row.type_id" + /> </template> </el-table-column> - <el-table-column label="供应商名称" prop="mer_name" show-overflow-tooltip /> - <el-table-column label="结算周期(天)" prop="settle_cycle" show-overflow-tooltip /> - <el-table-column label="利率" prop="interest_rate" show-overflow-tooltip /> + <el-table-column + label="供应商名称" + prop="mer_name" + show-overflow-tooltip + /> + <el-table-column + label="结算周期(天)" + prop="settle_cycle" + show-overflow-tooltip + /> + <el-table-column + label="利率" + prop="interest_rate" + show-overflow-tooltip + /> <!-- <el-table-column label="标签" prop="sys_labels_arr" @@ -78,14 +125,26 @@ }}</span> </template> </el-table-column> --> - <el-table-column label="供应商地址" prop="mer_address" show-overflow-tooltip /> + <el-table-column + label="供应商地址" + prop="mer_address" + show-overflow-tooltip + /> <el-table-column label="供应商是否禁用" prop="status"> <template #default="{ row }"> <dict-value :options="dictData.show_status" :value="row.status" /> </template> </el-table-column> - <el-table-column label="提成比例" prop="commission_rate" show-overflow-tooltip /> - <el-table-column label="供应商手续费单独设置" width="200" prop="commission_switch"> + <el-table-column + label="提成比例" + prop="commission_rate" + show-overflow-tooltip + /> + <el-table-column + label="供应商手续费单独设置" + width="200" + prop="commission_switch" + > <template #default="{ row }"> <!-- <dict-value :options="dictData.show_status" :value="row.commission_switch" /> --> {{ row.commission_switch ? "开启" : "关闭" }} @@ -98,22 +157,42 @@ /> <el-table-column label="操作" width="200" fixed="right"> <template #default="{ row }"> - <el-button v-perms="['supplier.supplier/edit']" type="primary" link @click="handleEdit(row)"> + <el-button + v-perms="['supplier.supplier/edit']" + type="primary" + link + @click="handleEdit(row)" + > 编辑 </el-button> - <el-button v-perms="['supplier.supplier/delete']" type="danger" link @click="handleDelete(row.id)"> + <el-button + v-perms="['supplier.supplier/delete']" + type="danger" + link + @click="handleDelete(row.id)" + > 删除 </el-button> <el-button link @click="handleDetail(row.id)"> 详情 </el-button> - <router-link :to="{ - path: 'bindGoods', - query: { - id: row.id, - }, - }"> - <el-button link type="primary"> 商品绑定 </el-button> - </router-link> - <el-button v-if="!row.uid" link @click="bindUser(row)" type="primary"> + + <el-button link type="primary"> + <router-link + :to="{ + path: 'bindGoods', + query: { + id: row.id, + }, + }" + > + 商品绑定 + </router-link> + </el-button> + <el-button + v-if="!row.uid" + link + @click="bindUser(row)" + type="primary" + > 绑定用户 </el-button> <el-button link @click="setBalance(row.id)"> 设置余额 </el-button> @@ -151,15 +230,17 @@ </el-radio-group> </el-form-item> <el-form-item label="金额" :label-width="100"> - <el-input v-model="balanceInfo.set_money" type="number" placeholder="请输入金额" /> + <el-input + v-model="balanceInfo.set_money" + type="number" + placeholder="请输入金额" + /> </el-form-item> </el-form> <template #footer> <div class="dialog-footer"> <el-button @click="showBalance = false">取消</el-button> - <el-button type="primary" @click="submitBalance"> - 确认 - </el-button> + <el-button type="primary" @click="submitBalance"> 确认 </el-button> </div> </template> </el-dialog> @@ -174,7 +255,7 @@ import { apiSupplierDelete, apiSupplierDetail, apiSupplierSetBalance, - apiSupplierBindUser + apiSupplierBindUser, } from "@/api/supplier"; import { timeFormat } from "@/utils/util"; import feedback from "@/utils/feedback"; @@ -246,7 +327,7 @@ const handleDetail = async (id: any) => { const showDialog = ref(false); const bindData = ref({ - id: "" + id: "", }); // 绑定用户 const bindUser = (data: any) => { @@ -261,7 +342,6 @@ const onBind = (data: any) => { showDialog.value = false; getLists(); }); - }; const balanceInfo = ref({ @@ -277,8 +357,9 @@ const setBalance = (id: any) => { balanceInfo.value.type = 1; showBalance.value = true; }; -const submitBalance = ()=>{ - if(+balanceInfo.value.set_money <=0 || balanceInfo.value.set_money == '') return ElMessage.error('请输入正确的金额'); +const submitBalance = () => { + if (+balanceInfo.value.set_money <= 0 || balanceInfo.value.set_money == "") + return ElMessage.error("请输入正确的金额"); apiSupplierSetBalance({ set_money: +balanceInfo.value.set_money, id: balanceInfo.value.id, @@ -287,7 +368,7 @@ const submitBalance = ()=>{ showBalance.value = false; getLists(); }); -} +}; getLists(); </script> diff --git a/src/views/goods/quote/detail.vue b/src/views/goods/quote/detail.vue new file mode 100644 index 0000000..ae25e2e --- /dev/null +++ b/src/views/goods/quote/detail.vue @@ -0,0 +1,111 @@ +<template> + <div class="edit-popup"> + <popup ref="popupRef" :async="true" width="550px" @close="handleClose" :bottom-btn="false"> + <el-descriptions class="margin-top" :title="popupTitle" :column="1" border> + <el-descriptions-item label="条码名称"> + {{ formData.name }} + </el-descriptions-item> + <el-descriptions-item label="条码内容"> + {{ formData.code }} + </el-descriptions-item> + <el-descriptions-item label="条码类型"> + <dict-value :options="dictData.code_type" :value="formData.type" /> + </el-descriptions-item> + <el-descriptions-item label="备注信息"> + {{ formData.data }} + </el-descriptions-item> + <el-descriptions-item label="扩展信息"> + {{ formData.more }} + </el-descriptions-item> + <el-descriptions-item label="排序"> + {{ formData.sort }} + </el-descriptions-item> + </el-descriptions> + </popup> + </div> +</template> + +<script lang="ts" setup name="brandEdit"> +import Popup from '@/components/popup/index.vue' +import type { PropType } from 'vue' +defineProps({ + dictData: { + type: Object as PropType<Record<string, any[]>>, + default: () => ({}) + } +}) +const emit = defineEmits(['success', 'close']) +const popupRef = shallowRef<InstanceType<typeof Popup>>() +const mode = ref('add') + + +// 弹窗标题 +const popupTitle = computed(() => { + return '品牌详情' +}) + +// 表单数据 +const formData = reactive({ + id: '', + name: '', + py: '', + code: '', + type: '', + data: '', + more: '', + sort: '', +}) + +// 表单验证 +const formRules = reactive<any>({ + name: [{ + required: true, + message: '请输入品牌名称', + trigger: ['blur'] + }] +}) + + +// 获取详情 +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 handleSubmit = async () => { +// await formRef.value?.validate() +// const data = { ...formData, } +// mode.value == 'edit' +// ? await apiBrandEdit(data) +// : await apiBrandAdd(data) +// popupRef.value?.close() +// emit('success') +// } + +//打开弹窗 +const open = (type = 'add') => { + mode.value = type + popupRef.value?.open() +} + +// 关闭回调 +const handleClose = () => { + emit('close') +} + + + +defineExpose({ + open, + setFormData, +}) +</script> diff --git a/src/views/goods/quote/edit.vue b/src/views/goods/quote/edit.vue new file mode 100644 index 0000000..888a2f0 --- /dev/null +++ b/src/views/goods/quote/edit.vue @@ -0,0 +1,144 @@ +<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="name"> + <el-input v-model="formData.name" clearable placeholder="请输入条码名称" /> + </el-form-item> + <!-- <el-form-item label="拼音信息" prop="py"> + <el-input v-model="formData.py" clearable placeholder="请输入拼音信息" /> + </el-form-item> --> + <el-form-item label="条码内容" prop="code"> + <el-input v-model="formData.code" clearable placeholder="请输入条码内容" /> + </el-form-item> + <el-form-item label="条码类型" prop="type"> + <el-select class="flex-1" v-model="formData.type" clearable placeholder="请选择条码类型"> + <el-option v-for="(item, index) in dictData.code_type" :key="index" :label="item.name" + :value="parseInt(item.value)" /> + </el-select> + </el-form-item> + <el-form-item label="备注信息" prop="data"> + <el-input v-model="formData.data" type="textarea" clearable placeholder="请输入备注信息" /> + </el-form-item> + <el-form-item label="扩展信息" prop="more"> + <el-input v-model="formData.more" type="textarea" clearable placeholder="请输入扩展信息" /> + </el-form-item> + <el-form-item label="排序" prop="sort"> + <el-input v-model="formData.sort" clearable placeholder="请输入排序" /> + </el-form-item> + </el-form> + </popup> + </div> +</template> + +<script lang="ts" setup name="codeEdit"> +import type { FormInstance } from 'element-plus' +import Popup from '@/components/popup/index.vue' +import { apiCodeAdd, apiCodeEdit, apiCodeDetail } from '@/api/code' +import { timeFormat } from '@/utils/util' +import type { PropType } from 'vue' +defineProps({ + dictData: { + type: Object as PropType<Record<string, any[]>>, + default: () => ({}) + } +}) +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: '', + name: '', + py: '', + code: '', + type: '', + data: '', + more: '', + sort: '', +}) + + +// 表单验证 +const formRules = reactive<any>({ + name: [{ + required: true, + message: '请输入条码名称', + trigger: ['blur'] + }], + py: [{ + required: true, + message: '请输入拼音信息', + trigger: ['blur'] + }], + code: [{ + required: true, + message: '请输入条码内容', + trigger: ['blur'] + }], + type: [{ + required: true, + message: '请选择条码类型0:条形码 | 1:二维码', + trigger: ['blur'] + }] +}) + + +// 获取详情 +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 getDetail = async (row: Record<string, any>) => { + const data = await apiCodeDetail({ + id: row.id + }) + setFormData(data) +} + + +// 提交按钮 +const handleSubmit = async () => { + await formRef.value?.validate() + const data = { ...formData, } + mode.value == 'edit' + ? await apiCodeEdit(data) + : await apiCodeAdd(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> diff --git a/src/views/goods/quote/index.vue b/src/views/goods/quote/index.vue new file mode 100644 index 0000000..e9d30e2 --- /dev/null +++ b/src/views/goods/quote/index.vue @@ -0,0 +1,76 @@ +<template> + <div> + <el-card class="!border-none mb-4" shadow="never"> + <el-form class="mb-[-16px]" :model="queryParams" inline> + <el-form-item label="条码名称" prop="name"> + <el-input + class="w-[280px]" + v-model="queryParams.name" + clearable + 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"> + <div class="mt-4"> + <el-table :data="pager.lists"> + <el-table-column label="ID" prop="id" width="55" /> + <el-table-column label="名称" prop="name" show-overflow-tooltip /> + <el-table-column label="商品款数" prop="nums" show-overflow-tooltip /> + <el-table-column label="状态" prop="status" show-overflow-tooltip> + <template #default="{ row }"> + <span v-if="row.status == 1">已报价</span> + <span v-if="row.status == 0" style="color: #f56c6c">待报价</span> + </template> + </el-table-column> + <el-table-column label="操作" width="170" fixed="right"> + <template #default="{ row }"> + <el-button link @click="handleDetail(row.id)" type="primary"> + <router-link + :to="{ + path: 'quoteOffer', + query: { + id: row.id, + date: row.name.substring(0, 10) + }, + }" + > + 立即报价 + </router-link> + </el-button> + </template> + </el-table-column> + </el-table> + </div> + <div class="flex mt-4 justify-end"> + <pagination v-model="pager" @change="getLists" /> + </div> + </el-card> + </div> +</template> + +<script lang="ts" setup name="codeLists"> +import { usePaging } from "@/hooks/usePaging"; +import { useDictData } from "@/hooks/useDictOptions"; +import { opurchaseGoodsOfferDateListsApi } from "@/api/quote"; +import feedback from "@/utils/feedback"; + +// 查询条件 +const queryParams = reactive({}); + +// 分页相关 +const { pager, getLists, resetParams, resetPage } = usePaging({ + fetchFun: opurchaseGoodsOfferDateListsApi, + params: queryParams, +}); + +getLists(); + +const handleDetail = (e) => {}; +</script> diff --git a/src/views/goods/quote/quoteOffer.vue b/src/views/goods/quote/quoteOffer.vue new file mode 100644 index 0000000..134a84b --- /dev/null +++ b/src/views/goods/quote/quoteOffer.vue @@ -0,0 +1,244 @@ +<template> + <div> + <el-card class="!border-none mb-4" shadow="never"> + <el-tabs v-model="activeName" class="demo-tabs" @tab-change="tabChange"> + <el-tab-pane label="待报价" name="tobe"> + <div class="flex mb-4"> + <el-button type="primary" @click="submit">提交报价</el-button> + </div> + <div + class="quote-list" + v-infinite-scroll="getLists(1)" + :infinite-scroll-distance="1000" + :infinite-scroll-delay="500" + :infinite-scroll-immediate="false" + style="overflow: auto" + > + <el-row :gutter="20" style="width: 100%"> + <el-col :span="8" v-for="(item, index) in list1" :key="index"> + <el-card> + <div class="flex justify-between"> + <div>名称: {{ item.goods_name }}</div> + <div> + 需求量: + <span style="color: #f56c6c">{{ item.need_num }}</span> + {{ item.unit_name }} + </div> + </div> + <div class="flex justify-between mt-4"> + <div class="flex" style="align-items: center"> + <span class="mr-2">提供数量: </span> + <el-input + v-model="item.nums" + placeholder="请输入可提供数量" + style="flex: 1" + ></el-input> + </div> + <div class="flex" style="align-items: center"> + <span class="mr-2">产品报价: </span> + <el-input + v-model="item.price" + placeholder="请输入产品报价" + style="flex: 1" + ></el-input> + </div> + </div> + <div class="flex justify-end mt-4"> + <div> + 共 {{ item.nums }} {{ item.unit_name }} 合计 + <span class="mx-1" style="color: #f56c6c">{{ + (item.nums * item.price).toFixed(2) + }}</span> + 元 + </div> + </div> + </el-card> + </el-col> + </el-row> + </div> + </el-tab-pane> + <el-tab-pane label="报价记录" name="yet"> + <div + class="quote-list not-btn" + v-infinite-scroll="getLists(1)" + :infinite-scroll-distance="1000" + :infinite-scroll-delay="500" + :infinite-scroll-immediate="false" + style="overflow: auto" + > + <el-row :gutter="20" style="width: 100%;"> + <el-col :span="8" v-for="(item, index) in list2" :key="index"> + <el-card> + <div class="flex justify-between"> + <div>名称: {{ item.goods_name }}</div> + <div> + 需求量: + <span style="color: #f56c6c">{{ item.need_num }}</span> + {{ item.unit_name }} + </div> + </div> + <div class="flex justify-between mt-4"> + <div + class="flex" + style="align-items: center; position: relative" + > + <span class="mr-2">提供数量: </span> + <el-input + v-model="item.nums" + placeholder="请输入可提供数量" + style="flex: 1" + readonly + ></el-input> + <div + style=" + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 100px; + " + > + <el-image + v-if="item.is_adopt == 1" + src="https://lihai001.oss-cn-chengdu.aliyuncs.com/attach/274ad202405111523222891.png" + ></el-image> + <el-image + v-else-if="item.is_adopt == 2" + src="https://lihai001.oss-cn-chengdu.aliyuncs.com/attach/739c3202405071458553459.png" + ></el-image> + <el-image + v-else + src="https://lihai001.oss-cn-chengdu.aliyuncs.com/attach/04c2c202405071501462462.png" + ></el-image> + </div> + </div> + <div class="flex" style="align-items: center"> + <span class="mr-2">产品报价: </span> + <el-input + v-model="item.price" + placeholder="请输入产品报价" + style="flex: 1" + readonly + ></el-input> + </div> + </div> + <div class="flex justify-end mt-4"> + <div> + 共 {{ item.nums }} {{ item.unit_name }} 合计 + <span class="mx-1" style="color: #f56c6c">{{ + (item.nums * item.price).toFixed(2) + }}</span> + 元 + </div> + </div> + </el-card> + </el-col> + </el-row> + </div> + + </el-tab-pane> + </el-tabs> + </el-card> + </div> +</template> + +<script lang="ts" setup name="quoteOffer"> +import { useRoute } from "vue-router"; +import { + opurchaseGoodsOfferListsApi, + opurchaseGoodsOfferOfferApi, +} from "@/api/quote"; + +const route = useRoute(); +const form = ref({}); + +const activeName = ref("tobe"); +const activeMap = ref( + new Map([ + ["detail", true], + ["yet", false], + ]) +); +const tabChange = (type: any) => { + if (type == "yet") { + list2.value = []; + getLists(2); + } else { + list1.value = []; + getLists(1); + } +}; + +const list1 = ref([]); +const list2 = ref([]); + +const queryParams = reactive({ + date: route.query.date, +}); + +const getLists = (e = 1) => { + opurchaseGoodsOfferListsApi({ + type: e, + ...queryParams, + }).then((res) => { + if (e == 1) { + list1.value = [...list1.value, ...res.lists]; + } else { + list2.value = [...list2.value, ...res.lists]; + } + }); +}; + +getLists(); + +const submit = () => { + let data = list1.value + .filter((item) => { + return +item.price && +item.nums; + }) + .map((item: any) => { + return { + id: item.id, + nums: item.nums, + price: item.price, + }; + }); + if (!data.length) return ElMessage.error("请先填写产品报价"); + opurchaseGoodsOfferOfferApi({ + data: data, + }).then((res) => { + getLists(); + }); +}; +</script> + +<style scoped lang="scss"> +.quote-list { + height: calc(100vh - 300px); + width: 100%; +} +.not-btn{ + height: calc(100vh - 252px); +} +/* 修改滚动条的样式 */ +::-webkit-scrollbar { + width: 0.315rem; /* 设置滚动条的宽度 */ +} + +/* 设置滚动条的轨道样式 */ +::-webkit-scrollbar-track { + background-color: #f1f1f1; /* 设置轨道的背景色 */ + margin: 1.25rem 0; +} + +/* 设置滚动条的滑块样式 */ +::-webkit-scrollbar-thumb { + background-color: #ccc; /* 设置滑块的背景色 */ + border-radius: 0.315rem; /* 设置滑块的圆角 */ +} + +/* 设置滚动条鼠标悬停时的滑块样式 */ +::-webkit-scrollbar-thumb:hover { + background-color: #999; /* 设置鼠标悬停时滑块的背景色 */ +} +</style> diff --git a/src/views/opurchase/opurchaseclass/index.vue b/src/views/opurchase/opurchaseclass/index.vue index 730a106..102a4c8 100644 --- a/src/views/opurchase/opurchaseclass/index.vue +++ b/src/views/opurchase/opurchaseclass/index.vue @@ -46,7 +46,7 @@ </template> 提交今日商户采购订单 </el-button> - <el-button + <!-- <el-button v-perms="['operation.opurchaseclass/add']" type="success" @click="onPrintOrder" @@ -55,10 +55,10 @@ <icon name="el-icon-Printer" /> </template> 打印 - </el-button> + </el-button> --> <div class="mt-4"> <el-table :data="pager.lists" @selection-change="handleSelectionChange"> - <el-table-column type="selection" width="55" /> + <!-- <el-table-column type="selection" width="55" /> --> <el-table-column label="ID" prop="id" show-overflow-tooltip /> <el-table-column label="所属商户" @@ -114,6 +114,9 @@ </el-table-column> <el-table-column label="操作" width="120" fixed="right"> <template #default="{ row }"> + <!-- <el-button type="primary" link @click="onPrintOrder(row)"> + 打印 + </el-button> --> <el-button type="primary" link @click="handleDetail(row)"> 详情 </el-button> @@ -166,10 +169,12 @@ import { useRouter } from "vue-router"; import { print, testPrint } from "@/utils/print"; // 下列方法都是没有拖拽设计页面的, 相当于代码模式, 使用代码设计页面 -const onPrintOrder = () => { - testPrint({ - name: 'test' - }) +const onPrintOrder = (row: any) => { + console.log(row); + + // testPrint({ + // name: 'test' + // }) }; const router = useRouter(); diff --git a/src/views/permission/admin/edit.vue b/src/views/permission/admin/edit.vue index decf6a5..12163c7 100644 --- a/src/views/permission/admin/edit.vue +++ b/src/views/permission/admin/edit.vue @@ -32,7 +32,7 @@ <el-form-item label="名称" prop="name"> <el-input v-model="formData.name" placeholder="请输入名称" clearable /> </el-form-item> - <el-form-item label="归属部门" prop="dept_id"> + <!-- <el-form-item label="归属部门" prop="dept_id"> <el-tree-select class="flex-1" v-model="formData.dept_id" @@ -51,7 +51,7 @@ :default-expand-all="true" placeholder="请选择上级部门" /> - </el-form-item> + </el-form-item> --> <el-form-item label="岗位" prop="jobs_id"> <el-select class="flex-1" diff --git a/src/views/translationOrder/index.vue b/src/views/translationOrder/index.vue index d1dc20b..964629d 100644 --- a/src/views/translationOrder/index.vue +++ b/src/views/translationOrder/index.vue @@ -38,7 +38,7 @@ </el-button> --> <div class="mt-4"> <el-table :data="pager.lists" @selection-change="handleSelectionChange"> - <el-table-column type="selection" width="55" /> + <!-- <el-table-column type="selection" width="55" /> --> <el-table-column label="ID" prop="id" show-overflow-tooltip /> <el-table-column label="所属商户"