diff --git a/.vscode/launch.json b/.vscode/launch.json index dd08d4d..a4e5aaf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -43,9 +43,10 @@ //南昌研发结束 // 镇江研发开始 "-g postgres://FashionAdmin:123456@10.8.30.36:5432/data_center", - "--redisHost localhost", + "--redisHost 10.8.30.112", "--redisPort 6379", - "--apiEmisUrl http://10.8.30.161:1111", + "--apiEmisUrl http://10.8.30.112:14000", //开发 + // "--apiEmisUrl http://10.8.30.161:1111", //测试 // 镇江研发结束 // 测试 "--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5", diff --git a/api/app/lib/controllers/auth/index.js b/api/app/lib/controllers/auth/index.js index cfcc1f1..76d2d73 100644 --- a/api/app/lib/controllers/auth/index.js +++ b/api/app/lib/controllers/auth/index.js @@ -9,9 +9,18 @@ async function login (ctx, next) { try { const params = ctx.request.body; - const emisLoginRes = await ctx.app.fs.emisRequest.post('login', { - data: params - }) + let emisLoginRes = null + if (params.username && params.password) { + emisLoginRes = await ctx.app.fs.emisRequest.post('login', { + data: { ...params, } + }) + } else if (params.token) { + emisLoginRes = await ctx.app.fs.emisRequest.get('user-info', { + query: { + token: params.token, + } + }) + } if (!emisLoginRes) { throw "无此用户,请使用正确的登录信息" diff --git a/api/app/lib/controllers/customerContactsFollup/index.js b/api/app/lib/controllers/customerContactsFollup/index.js new file mode 100644 index 0000000..612eed1 --- /dev/null +++ b/api/app/lib/controllers/customerContactsFollup/index.js @@ -0,0 +1,23 @@ +'use strict'; + +// 查询储备项目统计表 +async function getCustomerContactsFollowup(ctx, next) { + const { type } = ctx.params; + let rslt = null; + try { + rslt = await ctx.fs.dc.models.ReserveItemReport.findAll({ + order: [['id', 'DESC']], + // where: { type: type } + }) + ctx.status = 200 + ctx.body = rslt + } catch (error) { + ctx.fs.logger.error(`path:${ctx.path},error:${error}`) + ctx.status = 400; + ctx.body = { name: 'FindAllError', message: '获取失败' } + } +} + +module.exports = { + getCustomerContactsFollowup +} \ No newline at end of file diff --git a/api/app/lib/controllers/report/achievement.js b/api/app/lib/controllers/report/achievement.js index e0fc180..7a85527 100644 --- a/api/app/lib/controllers/report/achievement.js +++ b/api/app/lib/controllers/report/achievement.js @@ -324,6 +324,59 @@ async function importAchieveDetails(ctx) { } } +/** + * 查询合同明细表数据 + * @param {*} ctx ctx ctx.query:{keywordTarget-关键字项、keyword-关键字内容、limit-页宽, page-页码} + */ +async function getContractDetail(ctx) { + try { + const { models } = ctx.fs.dc; + const { keywordTarget, keyword, limit, page } = ctx.query; + const where = {}; + if (keywordTarget && keyword) { + where[keywordTarget] = { $iLike: `%${keyword}%` }; + } + let contractDetail = await models.ContractDetail.findAndCountAll({ + where: where, + offset: Number(page) * Number(limit), + limit: Number(limit), + order: [['id', 'DESC']] + }); + ctx.status = 200 + ctx.body = contractDetail; + } catch (error) { + ctx.fs.logger.error(`path:${ctx.path},error:${error}`) + ctx.status = 400; + ctx.body = { name: 'FindError', message: '查询合同明细表数据失败' } + } +} + +/** + * 查询开票明细表数据 + * @param {*} ctx ctx ctx.query:{keywordTarget-关键字项、keyword-关键字内容、limit-页宽, page-页码} + */ +async function getInvoicingDetail(ctx) { + try { + const { models } = ctx.fs.dc; + const { keywordTarget, keyword, limit, page } = ctx.query; + const where = {}; + if (keywordTarget && keyword) { + where[keywordTarget] = { $iLike: `%${keyword}%` }; + } + let invoiceDetail = await models.InvoiceDetail.findAndCountAll({ + where: where, + offset: Number(page) * Number(limit), + limit: Number(limit), + order: [['id', 'DESC']] + }); + ctx.status = 200 + ctx.body = invoiceDetail; + } catch (error) { + ctx.fs.logger.error(`path:${ctx.path},error:${error}`) + ctx.status = 400; + ctx.body = { name: 'FindError', message: '查询开票明细表数据失败' } + } +} module.exports = { getReceivedDetail,//回款 getAchievementDetail,//业绩 @@ -331,4 +384,6 @@ module.exports = { getReceivedNumbers,//查询回款明细表 已有的所有编号 importBackDetails,//导入回款明细 importAchieveDetails,//导入业绩明细 + getContractDetail, + getInvoicingDetail } \ No newline at end of file diff --git a/api/app/lib/models/customerContactsFollup.js b/api/app/lib/models/customerContactsFollup.js new file mode 100644 index 0000000..53537c1 --- /dev/null +++ b/api/app/lib/models/customerContactsFollup.js @@ -0,0 +1,65 @@ +/* eslint-disable*/ +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const ReserveItemReport = sequelize.define("reserveItemReport", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + field: "id", + autoIncrement: true, + }, + customer: { + type: DataTypes.STRING, + allowNull: true, + field: "customer", + }, + items: { + type: DataTypes.STRING, + allowNull: true, + field: "items", + }, + department: { + type: DataTypes.STRING, + allowNull: false, + field: "department", + }, + sale: { + type: DataTypes.STRING, + allowNull: true, + field: "sale", + }, + updatetime: { + type: DataTypes.DATE, + allowNull: false, + field: "updatetime", + }, + customerContacts: { + type: DataTypes.STRING, + allowNull: true, + field: "customer_contacts", + }, + phone: { + type: DataTypes.STRING, + allowNull: true, + field: "phone", + }, + visitStyle: { + type: DataTypes.STRING, + allowNull: true, + field: "visit_style", + }, + itemText: { + type: DataTypes.STRING, + allowNull: true, + field: "item_text", + } + }, { + tableName: "customer_contacts_followup", + }); + dc.models.ReserveItemReport = ReserveItemReport; + return ReserveItemReport; +}; \ No newline at end of file diff --git a/api/app/lib/routes/customerContactsFollup/index.js b/api/app/lib/routes/customerContactsFollup/index.js new file mode 100644 index 0000000..b8c0cee --- /dev/null +++ b/api/app/lib/routes/customerContactsFollup/index.js @@ -0,0 +1,8 @@ +'use strict'; + +const report = require('../../controllers/customerContactsFollup'); + +module.exports = function (app, router, opts) { + app.fs.api.logAttr['GET/customerContactsFollup'] = { content: '客户联系人对接跟进', visible: false }; + router.get('/customerContactsFollup', report.getReserveItemReport); +}; \ No newline at end of file diff --git a/api/app/lib/routes/report/index.js b/api/app/lib/routes/report/index.js index 8f712c0..8ae8752 100644 --- a/api/app/lib/routes/report/index.js +++ b/api/app/lib/routes/report/index.js @@ -27,4 +27,9 @@ module.exports = function (app, router, opts) { app.fs.api.logAttr['POST/add/achievement/bulk'] = { content: '导入业绩明细', visible: true }; router.post('/add/achievement/bulk', achieve.importAchieveDetails); + app.fs.api.logAttr['GET/contract/detail'] = { content: '查询合同明细表', visible: false }; + router.get('/contract/detail', achieve.getContractDetail); + + app.fs.api.logAttr['GET/invoicing/detail'] = { content: '查询开票明细表', visible: false }; + router.get('/invoicing/detail', achieve.getInvoicingDetail); }; \ No newline at end of file diff --git a/web/client/src/layout/containers/layout/index.jsx b/web/client/src/layout/containers/layout/index.jsx index 9c7eb26..37e2634 100644 --- a/web/client/src/layout/containers/layout/index.jsx +++ b/web/client/src/layout/containers/layout/index.jsx @@ -10,9 +10,13 @@ import { resize } from '../../actions/global'; import * as NProgress from 'nprogress'; import PerfectScrollbar from 'perfect-scrollbar'; import { useLocation } from "react-router"; +import { RouteTable } from '$utils'; +import { RouteRequest } from '@peace/utils'; +import Cookie from 'js-cookie'; +import { login, LOGIN_SUCCESS } from '../../../sections/auth/actions/auth'; NProgress.configure({ - template: ` + template: `
@@ -23,303 +27,354 @@ NProgress.configure({ }); let scrollbar +let requestUser = true +let requestlogout = false; + // const location111 = useLocation(); const LayoutContainer = props => { - const { - dispatch, msg, user, copyright, children, sections, clientWidth, clientHeight, - location, match, routes, history, socket, - } = props - const [collapsed, setCollapsed] = useState(false) + const { + dispatch,actions, msg, user, copyright, children, sections, clientWidth, clientHeight, + location, match, routes, history, socket, apiRoot + } = props + const [collapsed, setCollapsed] = useState(false) - NProgress.start(); + NProgress.start(); - const resize_ = () => { - dispatch(resize( - document.getElementById('DrApp').clientHeight, - document.getElementById('DrApp').clientWidth - (collapsed ? 120 : 240) - )); - } - function deepCopy(data) {//深拷贝 - //string,number,bool,null,undefined,symbol - //object,array,date - if (data && typeof data === "object") { - //针对函数的拷贝 - if (typeof data === "function") { - let tempFunc = data.bind(null); - tempFunc.prototype = deepCopy(data.prototype); - return tempFunc; - } + const resize_ = () => { + dispatch(resize( + document.getElementById('DrApp').clientHeight, + document.getElementById('DrApp').clientWidth - (collapsed ? 120 : 240) + )); + } + function deepCopy (data) {//深拷贝 + //string,number,bool,null,undefined,symbol + //object,array,date + if (data && typeof data === "object") { + //针对函数的拷贝 + if (typeof data === "function") { + let tempFunc = data.bind(null); + tempFunc.prototype = deepCopy(data.prototype); + return tempFunc; + } - switch (Object.prototype.toString.call(data)) { - case "[object String]": - return data.toString(); - case "[object Number]": - return Number(data.toString()); - case "[object Boolean]": - return new Boolean(data.toString()); - case "[object Date]": - return new Date(data.getTime()); - case "[object Array]": - var arr = []; - for (let i = 0; i < data.length; i++) { - arr[i] = deepCopy(data[i]); - } - return arr; + switch (Object.prototype.toString.call(data)) { + case "[object String]": + return data.toString(); + case "[object Number]": + return Number(data.toString()); + case "[object Boolean]": + return new Boolean(data.toString()); + case "[object Date]": + return new Date(data.getTime()); + case "[object Array]": + var arr = []; + for (let i = 0; i < data.length; i++) { + arr[i] = deepCopy(data[i]); + } + return arr; - //js自带对象或用户自定义类实例 - case "[object Object]": - var obj = {}; - for (let key in data) { - //会遍历原型链上的属性方法,可以用hasOwnProperty来控制 (obj.hasOwnProperty(prop) - obj[key] = deepCopy(data[key]); - } - return obj; - } - } else { - //string,number,bool,null,undefined,symbol - return data; - } - } - const [allItems, setAllItems] = useState([]) - // const [headerItems, setHeaderItems] = useState([]) - const [leftItems, setLeftItems] = useState([]) - const [leftChange, setLeftChange] = useState(true) - const [leftShow, setLeftShow] = useState(false) - useEffect(() => { - let topItems = []//头部导航 - const lastSelectedKeys = localStorage.getItem('poms_selected_sider') - let nextItems = []//所有导航 - for (let c of sections) { - if (typeof c.getNavItem == 'function') { - let item = c.getNavItem(user, dispatch); - if (item) { - nextItems.push.apply(nextItems, item) - if (item.length > 0) { - for (let j = 0; j < item.length; j++) { - let itm = deepCopy(item[j]); - if (itm.hasOwnProperty('items')) { - for (let i = 0; i < itm.items.length; i++) { - itm.items[i].fatherKey = itm.itemKey - delete itm.items[i].items - } - // topItems.push(itm) - // } - // else { - // topItems.push.apply(topItems, item) - } + //js自带对象或用户自定义类实例 + case "[object Object]": + var obj = {}; + for (let key in data) { + //会遍历原型链上的属性方法,可以用hasOwnProperty来控制 (obj.hasOwnProperty(prop) + obj[key] = deepCopy(data[key]); + } + return obj; + } + } else { + //string,number,bool,null,undefined,symbol + return data; + } + } + const [allItems, setAllItems] = useState([]) + // const [headerItems, setHeaderItems] = useState([]) + const [leftItems, setLeftItems] = useState([]) + const [leftChange, setLeftChange] = useState(true) + const [leftShow, setLeftShow] = useState(false) + useEffect(() => { + let topItems = []//头部导航 + const lastSelectedKeys = localStorage.getItem('poms_selected_sider') + let nextItems = []//所有导航 + for (let c of sections) { + if (typeof c.getNavItem == 'function') { + let item = c.getNavItem(user, dispatch); + if (item) { + nextItems.push.apply(nextItems, item) + if (item.length > 0) { + for (let j = 0; j < item.length; j++) { + let itm = deepCopy(item[j]); + if (itm.hasOwnProperty('items')) { + for (let i = 0; i < itm.items.length; i++) { + itm.items[i].fatherKey = itm.itemKey + delete itm.items[i].items } - } - } + // topItems.push(itm) + // } + // else { + // topItems.push.apply(topItems, item) + } + } + } } - } - setAllItems(nextItems) - // setHeaderItems(topItems) - if (lastSelectedKeys) {//如果有缓存 - for (let i = 0; i < nextItems.length; i++) { - if (JSON.parse(lastSelectedKeys)[0] == nextItems[i].itemKey) { + } + } + setAllItems(nextItems) + // setHeaderItems(topItems) + if (lastSelectedKeys) {//如果有缓存 + for (let i = 0; i < nextItems.length; i++) { + if (JSON.parse(lastSelectedKeys)[0] == nextItems[i].itemKey) { - // let openArr = [] - // for (let j = 0; j < nextItems[i].items.length; j++) { - // openArr.push(nextItems[i].items[j].itemKey) - // } - // localStorage.setItem('poms_open_sider', JSON.stringify(openArr)) - setLeftItems(nextItems[i].items) - } + // let openArr = [] + // for (let j = 0; j < nextItems[i].items.length; j++) { + // openArr.push(nextItems[i].items[j].itemKey) + // } + // localStorage.setItem('poms_open_sider', JSON.stringify(openArr)) + setLeftItems(nextItems[i].items) } - setLeftShow(true) - } - else { - setLeftShow(false) - } + } + setLeftShow(true) + } + else { + setLeftShow(false) + } - window.addEventListener('resize', resize_); - return () => { - window.removeEventListener('resize', resize_); - } - }, []) + window.addEventListener('resize', resize_); + return () => { + window.removeEventListener('resize', resize_); + } + }, []) - useEffect(() => { - let pathnameArr = location.pathname.split('/') - let openArr = [] - for (let i = 0; i < allItems.length; i++) { - if (allItems[i].items) { - for (let j = 0; j < allItems[i].items.length; j++) { - if (allItems[i].items[j].items) { - for (let k = 0; k < allItems[i].items[j].items.length; k++) { - if (allItems[i].items[j].items[k].to == location.pathname) { - for (let o = 0; o < allItems[i].items.length; o++) { - openArr.push(allItems[i].items[o].itemKey) - } - localStorage.setItem('poms_selected_sider', JSON.stringify([pathnameArr[1]])) - // localStorage.setItem('poms_open_sider', JSON.stringify(openArr)) - setLeftItems(allItems[i].items) - setLeftShow(true) - } + useEffect(() => { + let pathnameArr = location.pathname.split('/') + let openArr = [] + for (let i = 0; i < allItems.length; i++) { + if (allItems[i].items) { + for (let j = 0; j < allItems[i].items.length; j++) { + if (allItems[i].items[j].items) { + for (let k = 0; k < allItems[i].items[j].items.length; k++) { + if (allItems[i].items[j].items[k].to == location.pathname) { + for (let o = 0; o < allItems[i].items.length; o++) { + openArr.push(allItems[i].items[o].itemKey) } - } - } + localStorage.setItem('poms_selected_sider', JSON.stringify([pathnameArr[1]])) + // localStorage.setItem('poms_open_sider', JSON.stringify(openArr)) + setLeftItems(allItems[i].items) + setLeftShow(true) + } + } + } } - } - }, [location]) + } + } + }, [location]) - useEffect(() => { - NProgress.done(); - if ((!user || !user.authorized)) { - history.push('/signin'); - } - if (msg) { - if (msg.done) { - Notification.success({ - // title: msg.done, - content: msg.done, - duration: 2, - }) - } - if (msg.error) { - Notification.error({ - // title: msg.error, - content: msg.error, - duration: 2, - }) - } - } - const dom = document.getElementById('page-content'); - if (dom) { - if (!scrollbar) { - scrollbar = new PerfectScrollbar('#page-content', { suppressScrollX: true }); - scrollbar.update(); - } else { - scrollbar.update(); - dom.scrollTop = 0; - } - } - }) + useEffect(() => { + NProgress.done(); + if ((!user || !user.authorized)) { + // history.push('/signin'); + getUserInfoByToken() + } + if (msg) { + if (msg.done) { + Notification.success({ + // title: msg.done, + content: msg.done, + duration: 2, + }) + } + if (msg.error) { + Notification.error({ + // title: msg.error, + content: msg.error, + duration: 2, + }) + } + } + const dom = document.getElementById('page-content'); + if (dom) { + if (!scrollbar) { + scrollbar = new PerfectScrollbar('#page-content', { suppressScrollX: true }); + scrollbar.update(); + } else { + scrollbar.update(); + dom.scrollTop = 0; + } + } + }) + const getUserInfoByToken = () => { + if (requestUser) { + requestUser = false; + console.log(RouteTable.apiRoot); + RouteRequest.get(RouteTable.apiRoot).then(res => { + let token = Cookie.get('pepToken', { domain: res.domain }); + console.log(token); + dispatch(login({ token })).then(res => { + console.log(res); + if (res.type == 'LOGIN_SUCCESS') { + const data = res.payload?.user || {} + history.push('/businessManagement/pmReport/reserveItemsReporting') + localStorage.setItem('poms_open_sider', JSON.stringify(["pmReport"])) + localStorage.setItem('poms_selected_sider', JSON.stringify(["businessManagement"])) + localStorage.setItem('word', JSON.stringify('')) //系统登录代码时候存的,不清楚意义 + dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, hrUserId: data.hrUserInfo && hrUserInfo.id })) + } else { + redirectToLogin(true); + } + }, error => { + redirectToLogin(true); + }) + }, error => { + message.error('鉴权失败', 5); + redirectToLogin(true); + }) + } + } - // websocket 使用测试 - useEffect(() => { - // console.log(socket) - if (socket) { - socket.on('CAMERA_ONLINE', function (msg) { - console.info(msg); - if (msg.online == 'ON') { - Notification.success({ - title: 'Hi', - content: (