lc18518571399 9 months ago
commit
b5046f3f57
  1. 1
      api/.eslintignore
  2. 4
      api/.eslintrc
  3. 15
      api/.gitignore
  4. 31
      api/README.md
  5. 17
      api/agent.js
  6. 47
      api/app.js
  7. 10
      api/app/controller/chanpin.js
  8. 10
      api/app/controller/dingdan.js
  9. 10
      api/app/controller/exportData.js
  10. 10
      api/app/controller/user.js
  11. 606
      api/app/model/chanpin.js
  12. 151
      api/app/model/dingdan.js
  13. 50
      api/app/model/user.js
  14. 810
      api/app/public/chanpin.json
  15. 180
      api/app/public/dingdan.json
  16. 40
      api/app/public/user.json
  17. 11
      api/app/router.js
  18. 67
      api/app/service/chanpin.js
  19. 191
      api/app/service/dingdan.js
  20. 23
      api/app/service/exportData.js
  21. 67
      api/app/service/user.js
  22. 58
      api/config/config.default.js
  23. 11
      api/config/plugin.js
  24. 5
      api/jsconfig.json
  25. 40
      api/package.json
  26. 23
      api/test/app/controller/home.test.js
  27. 9
      front/.editorconfig
  28. 4
      front/.gitignore
  29. 1
      front/.npmrc
  30. 6
      front/.prettierignore
  31. 6
      front/.prettierrc
  32. 34
      front/README.md
  33. 12
      front/build/entitlements.mac.plist
  34. BIN
      front/build/icon.icns
  35. BIN
      front/build/icon.ico
  36. 36
      front/build/notarize.js
  37. 43
      front/electron-builder.yml
  38. 28
      front/electron.vite.config.js
  39. 6
      front/jsconfig.json
  40. 6161
      front/package-lock.json
  41. 41
      front/package.json
  42. BIN
      front/public/icon/icon.jpg
  43. 78
      front/src/main/index.js
  44. 21
      front/src/preload/dl.js
  45. 21
      front/src/preload/index.js
  46. 18
      front/src/renderer/index.html
  47. 84
      front/src/renderer/src/App.vue
  48. 20
      front/src/renderer/src/assets/css/base.css
  49. 810
      front/src/renderer/src/assets/json/chanpin.json
  50. 206
      front/src/renderer/src/assets/json/dingdan.json
  51. 40
      front/src/renderer/src/assets/json/user.json
  52. 83
      front/src/renderer/src/components/dingdanformcomponent.vue
  53. 136
      front/src/renderer/src/components/dingdantablecomponent.vue
  54. 77
      front/src/renderer/src/components/formcomponent.vue
  55. 120
      front/src/renderer/src/components/tablecomponent.vue
  56. 28
      front/src/renderer/src/main.js
  57. 358
      front/src/renderer/src/views/chanpin.vue
  58. 492
      front/src/renderer/src/views/dingdan.vue
  59. 359
      front/src/renderer/src/views/user.vue
  60. BIN
      模版/S6直营销售单导入模板.xls
  61. BIN
      模版/产品信息(模板).xls
  62. BIN
      模版/客户编码文档(1).xls
  63. BIN
      模版/销售订单修改导出(审核版).xlsx
  64. BIN
      模版/销售订单导入准备表(1).xlsx
  65. BIN
      模版/销售订单导出第一步(未审核版).xlsx
  66. BIN
      模版/销售订单未导入产品.xlsx

1
api/.eslintignore

@ -0,0 +1 @@
coverage

4
api/.eslintrc

@ -0,0 +1,4 @@
{
"extends": "eslint-config-egg",
"root": true
}

15
api/.gitignore

@ -0,0 +1,15 @@
logs/
npm-debug.log
yarn-error.log
node_modules/
*-lock.json
*-lock.yaml
yarn.lock
coverage/
.idea/
run/
.DS_Store
*.sw*
*.un~
typings/
.nyc_output/

31
api/README.md

@ -0,0 +1,31 @@
# back
back
## QuickStart
<!-- add docs here for user -->
see [egg docs][egg] for more detail.
### Development
```bash
npm i
npm run dev
open http://localhost:7001/
```
### Deploy
```bash
npm start
npm stop
```
### npm scripts
- Use `npm run lint` to check code style.
- Use `npm test` to run unit test.
[egg]: https://eggjs.org

17
api/agent.js

@ -0,0 +1,17 @@
// agent.js
module.exports = agent => {
// 在这里写你的初始化逻辑。
// 你还可以通过 messenger 对象发送消息给 App Worker。
// 但是,需要等 App Worker 启动成功后才能发送,否则可能丢失消息。
agent.messenger.on('egg-ready', () => {
// let params = {
// subType: "add",
// name: "admin",
// password: md5("admin"),
// email: "admin@admin.com",
// allowRegist: true,
// }
// agent.messenger.sendToApp('createAdmin', params);
});
};

47
api/app.js

@ -0,0 +1,47 @@
// app.js
class AppBootHook {
constructor(app) {
this.app = app;
}
configWillLoad() {
// 此时 config 文件已经被读取并合并,但还并未生效
// 这是应用层修改配置的最后机会
// 注意:此函数只支持同步调用
}
async didLoad() {
// 所有配置已经加载完毕
// 可以用来加载应用自定义的文件,启动自定义服务
}
async willReady() {
// 所有插件已启动完毕,但应用整体尚未 ready
// 可进行数据初始化等操作,这些操作成功后才启动应用
}
async didReady() {
// 应用已启动完毕
}
async serverDidReady() {
// // http/https 服务器已启动,开始接收外部请求
// // 此时可以从 app.server 获取 server 实例
// const ctx = await this.app.createAnonymousContext();
// this.app.messenger.on('createAdmin', async params => {
// let res = await ctx.model.User.find({ name: params.name });
// if (!res.length) {
// await ctx.service.user.index(params)
// }
// });
}
}
module.exports = AppBootHook;

10
api/app/controller/chanpin.js

@ -0,0 +1,10 @@
const { Controller } = require('egg');
class ChanpinController extends Controller {
async index() {
const { ctx } = this;
ctx.body = await ctx.service.chanpin.index(ctx.request.body)
}
}
module.exports = ChanpinController;

10
api/app/controller/dingdan.js

@ -0,0 +1,10 @@
const { Controller } = require('egg');
class DingdanController extends Controller {
async index() {
const { ctx } = this;
ctx.body = await ctx.service.dingdan.index(ctx.request.body)
}
}
module.exports = DingdanController;

10
api/app/controller/exportData.js

@ -0,0 +1,10 @@
const { Controller } = require('egg');
class ExportDataController extends Controller {
async index() {
const { ctx } = this;
ctx.body = await ctx.service.exportData.index(ctx.request.body)
}
}
module.exports = ExportDataController;

10
api/app/controller/user.js

@ -0,0 +1,10 @@
const { Controller } = require('egg');
class UserController extends Controller {
async index() {
const { ctx } = this;
ctx.body = await ctx.service.user.index(ctx.request.body)
}
}
module.exports = UserController;

606
api/app/model/chanpin.js

@ -0,0 +1,606 @@
'use strict';
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ChanpinSchema = new Schema({
// 创建时间
create_at: {
type: Date,
default: Date.now
},
// 更新时间
update_at: {
type: Date,
default: Date.now
},
// 代码
daima: {
type: String,
default: "",
index: true,
unique: true
},
// 品名
pinming: {
type: String,
default: ""
},
// 规格型号
guigexinghao: {
type: String,
default: ""
},
// 助记符
zhujifu: {
type: String,
default: ""
},
// 计量单位
jiliangdanwei: {
type: String,
default: ""
},
// 条形码
tiaoxingma: {
type: String,
default: "",
index: true,
},
// 箱装量
xiangzhuangliang: {
type: Number,
default: 0
},
// 箱装单位
xiangzhuangdanwei: {
type: String,
default: ""
},
// 最大单位箱装量
zuidadanweixiangzhuangliang: {
type: Number,
default: 0
},
// 最大箱装单位
zuidaxiangzhuangdanwei: {
type: String,
default: ""
},
// 产地
chandi: {
type: String,
default: ""
},
// 主供应商
zhugongyingshang: {
type: String,
default: ""
},
// 经销商
jingxiaoshang: {
type: String,
default: ""
},
// 所属类别
suoshuleibie: {
type: String,
default: ""
},
// 最高采购价
zuigaocaigoujia: {
type: Number,
default: 0
},
// 商超价1
shangchaojia1: {
type: Number,
default: 0
},
// 现金价
xianjinjia: {
type: Number,
default: 0
},
// 二批流通价
erpiliutongjia: {
type: Number,
default: 0
},
// 商超价
shangchaojia: {
type: Number,
default: 0
},
// 现金零售价
xianjinlingshoujia: {
type: Number,
default: 0
},
// 商超零售价
shangchaolingshoujia: {
type: Number,
default: 0
},
// 特通价
tetongjia: {
type: Number,
default: 0
},
// 分公司价
fengongsijia: {
type: Number,
default: 0
},
// 零食店价
shangchaolingshoujia: {
type: Number,
default: 0
},
// 初中高中价
chuzhonggaozhongjia: {
type: Number,
default: 0
},
// 车销价
chexiaojia: {
type: Number,
default: 0
},
// 发货价11
shangchaolingshoujia: {
type: Number,
default: 0
},
// 发货价12
fahuojia12: {
type: Number,
default: 0
},
// 进货税率%
jinhuoshuilv: {
type: Number,
default: 0
},
// 发货税率%
fahuoshuilv: {
type: Number,
default: 0
},
// 包装
baozhuang: {
type: String,
default: ""
},
// 毛利率
maolilv: {
type: Number,
default: 0
},
// 主存放仓库
zhucunfangcangku: {
type: String,
default: ""
},
// 有保质期
youbaozhiqi: {
type: String,
default: ""
},
// 保质期(天)
baozhiqi: {
type: Number,
default: 0
},
// 有效?
youxiao: {
type: String,
default: ""
},
// 采销类型
caixiaoleixing: {
type: String,
default: ""
},
// 商品类型
shangpinleixing: {
type: String,
default: ""
},
// 备注
beizhu: {
type: String,
default: ""
},
// 单位重量
danweizhongliang: {
type: Number,
default: 0
},
// 品牌
pinpai: {
type: String,
default: ""
},
// 单位体积(立方米)
danweitiji: {
type: Number,
default: 0
},
// 箱重量(kg)
xiangzhongliang: {
type: Number,
default: 0
},
// 最大单位重量(kg)
zuidadanweizhongliang: {
type: Number,
default: 0
},
// 箱体积(立方米)
xiangtiji: {
type: Number,
default: 0
},
// 最大单位体积(立方米)
zuidadanweitiji: {
type: Number,
default: 0
},
// 描述
miaoshu: {
type: String,
default: ""
},
// 仓库出入库时,以‘箱装单位’为依准
yixiangzhuangdanweiweiyizhun: {
type: String,
default: ""
},
// 打印‘流通随行单’
liutongsuixingdan: {
type: String,
default: ""
},
// 发货产品
fahuochanpin: {
type: String,
default: ""
},
// 标准核算价
biaozhunhesuanjia: {
type: Number,
default: 0
},
// 建议零售价
jianyilingshoujia: {
type: Number,
default: 0
},
// 最近一次采购价
zuijinyicicaigoujia: {
type: Number,
default: 0
},
// 最近一次销售价
zuijinyicixiaoshoujia: {
type: Number,
default: 0
},
// 箱条形码
xiangtiaoxingma: {
type: String,
default: "",
index: true,
},
// 最大箱装条码
zuidaxiangzhuangtiaoma: {
type: String,
default: "",
index: true,
},
// 接口编码1
jiekoubianma1: {
type: String,
default: ""
},
// 接口编码2
jiekoubianma2: {
type: String,
default: ""
},
// 接口编码3
jiekoubianma3: {
type: String,
default: ""
},
// 发货产品基数
fahuochanpinjishu: {
type: Number,
default: 0
},
// 采购最少数量
caigouzuishaoshuliang: {
type: Number,
default: 0
},
// 采购倍数
caigoubeishu: {
type: Number,
default: 0
},
// 采购滚动基数
caigougundongjishu: {
type: Number,
default: 0
},
// 最小单位产品
zuixiaodanweichanpin: {
type: String,
default: ""
},
// 最小单位倍数
zuixiaodanweibeishu: {
type: Number,
default: 0
},
// 产品归类
chanpinguilei: {
type: String,
default: ""
},
// 产品归类II
chanpinguilei2: {
type: String,
default: ""
},
// 箱单位最高采购价
xiangdanweizuigaocaigoujia: {
type: Number,
default: 0
},
// 箱单位商超价1
xiangdanweishangchaojia1: {
type: Number,
default: 0
},
// 箱单位现金价
xiangdanweixianjinjia: {
type: Number,
default: 0
},
// 箱单位二批流通价
xiangdanweierpiliutongjia: {
type: Number,
default: 0
},
// 箱单位商超价
xiangdanweishangchaojia: {
type: Number,
default: 0
},
// 箱单位现金零售价
xiangdanweixianjinlingshoujia: {
type: Number,
default: 0
},
// 箱单位商超零售价
xiangdanweishangchaolingshoujia: {
type: Number,
default: 0
},
// 箱单位特通价
xiangdanweitetongjia: {
type: Number,
default: 0
},
// 箱单位分公司价
xiangdanweifengongsijia: {
type: Number,
default: 0
},
// 箱单位零食店价
xiangdanweilingshidianjia: {
type: Number,
default: 0
},
// 箱单位初中高中价
xiangdanweichuzhonggaozhongjia: {
type: Number,
default: 0
},
// 箱单位车销价
xiangdanweichexiaojia: {
type: Number,
default: 0
},
// 箱单位发货价11
xiangdanweifahuojia11: {
type: Number,
default: 0
},
// 箱单位发货价12
xiangdanweifahuojia12: {
type: Number,
default: 0
},
// 最大单位最高采购价
zuidadanweizuigaocaigoujia: {
type: Number,
default: 0
},
// 最大单位商超价1
zuidadanweishangchaojia1: {
type: Number,
default: 0
},
// 最大单位现金价
zuidadanweixianjinjia: {
type: Number,
default: 0
},
// 最大单位二批流通价
zuidadanweierpiliutongjia: {
type: Number,
default: 0
},
// 最大单位商超价
zuidadanweishangchaojia: {
type: Number,
default: 0
},
// 最大单位现金零售价
zuidadanweixianjinlingshoujia: {
type: Number,
default: 0
},
// 最大单位商超零售价
zuidadanweishangchaolingshoujia: {
type: Number,
default: 0
},
// 最大单位特通价
zuidadanweitetongjia: {
type: Number,
default: 0
},
// 最大单位分公司价
zuidadanweifengongsijia: {
type: Number,
default: 0
},
// 最大单位零食店价
zuidadanweilingshidianjia: {
type: Number,
default: 0
},
// 最大单位初中高中价
zuidadanweichuzhonggaozhongjia: {
type: Number,
default: 0
},
// 最大单位车销价
zuidadanweichexiaojia: {
type: Number,
default: 0
},
// 最大单位发货价11
zuidadanweifahuojia11: {
type: Number,
default: 0
},
// 最大单位发货价12
zuidadanweifahuojia12: {
type: Number,
default: 0
},
// 默认单据单位
morendanjudanwei: {
type: String,
default: ""
},
// 不封箱单位
bufengxiangdanwei: {
type: String,
default: ""
},
// 仓库提成类别
cangkutichengleibie: {
type: String,
default: ""
},
// 强制批次管理
qiangzhipiciguanli: {
type: String,
default: ""
},
// 立库存放区域
likucunfangquyu: {
type: String,
default: ""
},
// 建档日期
jiandangriqi: {
type: Date,
default: Date.now
},
// 出货是否加工
chuhuoshifujiagong: {
type: String,
default: ""
},
// 保质期天数需大于
baozhiqitianshuxudayu: {
type: Number,
default: 0
},
// 单品重量误差
danpinzhongliangwucha: {
type: Number,
default: 0
},
// 最大单品重量误差百分比%
zuidadanpinzhongliangwuchabaifenbi: {
type: Number,
default: 0
},
// 最大箱重量误差
zuidaxiangzhongliangwucha: {
type: Number,
default: 0
},
// 价格调整时间
jiagediaozhengshijian: {
type: Date,
default: Date.now
},
// 录入人
lururen: {
type: String,
default: ""
},
// 允收天数
yunshoutianshu: {
type: Number,
default: 0
},
// 强制序列号管理
qiangzhixuliehaoguanli: {
type: String,
default: ""
},
// 国标条形码
guobiaotiaoxingma: {
type: String,
default: ""
},
// 长(cm)
chang: {
type: Number,
default: 0
},
// 宽(cm)
kuan: {
type: Number,
default: 0
},
// 高(cm)
gao: {
type: Number,
default: 0
},
// 每托盘件数
meituopanjianshu: {
type: Number,
default: 0
},
//数据是否删除
isExit: {
type: Number,
default: 1,
index: true
},
}, { strict: false });
return mongoose.model('Chanpin', ChanpinSchema);
};

151
api/app/model/dingdan.js

@ -0,0 +1,151 @@
'use strict';
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const DingdanSchema = new Schema({
// 创建时间
create_at: {
type: Date,
default: Date.now
},
// 更新时间
update_at: {
type: Date,
default: Date.now
},
// 客户编号
kehubianhao: {
type: String,
default: ""
},
// 简称
username: {
type: String,
default: ""
},
// 客户名称
kehumingcheng: {
type: String,
default: ""
},
// 产品代码
chanpindaima: {
type: String,
default: ""
},
// 厂编
changbian: {
type: String,
default: ""
},
// 货号
huohao: {
type: String,
default: ""
},
// 单据单位数量
danjudanweishuliang: {
type: Number,
default: 0
},
// 条码
tiaoma: {
type: String,
default: ""
},
// 最小单位条码
zuixiaodanweitiaoma: {
type: String,
default: ""
},
// 修改后销售数量
xiugaihouxiaoshoushuliang: {
type: Number,
default: 0
},
// 最高采购价
zuigaocaigoujia: {
type: Number,
default: 0
},
// 箱装量
xiangzhuangliang: {
type: Number,
default: 0
},
// 最大箱装量
zuidaxiangzhuangliang: {
type: Number,
default: 0
},
// 规格型号
guigexinghao: {
type: String,
default: ""
},
// 计量单位
jiliangdanwei: {
type: String,
default: ""
},
// 箱条码
xiangtiaoma: {
type: String,
default: ""
},
// 最大箱条码
zuidaxiangtiaoma: {
type: String,
default: ""
},
// 条码
tiaoma: {
type: String,
default: ""
},
// 品名
pinming: {
type: String,
default: ""
},
// 品名选项
pinmingxuanxiang: {
type: Array,
default: []
},
// 单位
danwei: {
type: String,
default: ""
},
// 规格
guige: {
type: String,
default: ""
},
// 销售数量
xiaoshoushuliang: {
type: Number,
default: 0
},
// 销售金额
xiaoshoujine: {
type: Number,
default: 0
},
//是否售卖
isNotSale: {
type: Boolean,
default: true,
},
//数据是否删除
isExit: {
type: Number,
default: 1,
index: true
},
}, { strict: false });
return mongoose.model('Dingdan', DingdanSchema);
};

50
api/app/model/user.js

@ -0,0 +1,50 @@
'use strict';
const { uniq } = require("lodash");
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const UserSchema = new Schema({
// 创建时间
create_at: {
type: Date,
default: Date.now
},
// 更新时间
update_at: {
type: Date,
default: Date.now
},
// 客户编号
usercode: {
type: Number,
default: 0,
index: true,
unique: true
},
// 简称
username: {
type: String,
default: ""
},
// 业务员
salesman: {
type: String,
default: ""
},
// 地址
address: {
type: String,
default: ""
},
//数据是否删除
isExit: {
type: Number,
default: 1,
index: true
},
}, { strict: false });
return mongoose.model('User', UserSchema);
};

810
api/app/public/chanpin.json

@ -0,0 +1,810 @@
[
{
"label": "创建时间",
"prop": "create_at",
"type": "date"
},
{
"label": "更新时间",
"prop": "update_at",
"type": "date"
},
{
"label": "代码",
"prop": "daima",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "品名",
"prop": "pinming",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "规格型号",
"prop": "guigexinghao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "助记符",
"prop": "zhujifu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "计量单位",
"prop": "jiliangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "条形码",
"prop": "tiaoxingma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "箱装量",
"prop": "xiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱装单位",
"prop": "xiangzhuangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装量",
"prop": "zuidadanweixiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装单位",
"prop": "zuidaxiangzhuangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "产地",
"prop": "chandi",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "主供应商",
"prop": "zhugongyingshang",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "经销商",
"prop": "jingxiaoshang",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "所属类别",
"prop": "suoshuleibie",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最高采购价",
"prop": "zuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "商超价1",
"prop": "shangchaojia1",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "现金价",
"prop": "xianjinjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "二批流通价",
"prop": "erpiliutongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "商超价",
"prop": "shangchaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "现金零售价",
"prop": "xianjinlingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "商超零售价",
"prop": "shangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "特通价",
"prop": "tetongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "分公司价",
"prop": "fengongsijia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "零食店价",
"prop": "shangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "初中高中价",
"prop": "chuzhonggaozhongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "车销价",
"prop": "chexiaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "发货价11",
"prop": "fahuojia11",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "发货价12",
"prop": "fahuojia12",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "进销税税率%",
"prop": "jinxiaoshuilv",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "发货税税率%",
"prop": "fahuoshuilv",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "包装",
"prop": "baozhuang",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "毛利率",
"prop": "maolilv",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "主存放仓库",
"prop": "zhucunfangcangku",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "有保质期",
"prop": "youbaozhiqi",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "保质期(天)",
"prop": "baozhiqi",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "有效",
"prop": "youxiao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "采销类型",
"prop": "caixiaoleixing",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "商品类型",
"prop": "shangpinleixing",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "备注",
"prop": "beizhu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "单位重量",
"prop": "danweizhongliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "品牌",
"prop": "pinpai",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "单位体积(立方米)",
"prop": "danweitiji",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱重量(kg)",
"prop": "xiangzhongliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位重量(kg)",
"prop": "zuidadanweizhongliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱体积(立方米)",
"prop": "xiangtiji",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "描述",
"prop": "miaoshu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "仓库出入库时,以‘箱装单位’为依准",
"prop": "yixiangzhuangdanweiweiyizhun",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "打印‘流通随行单’",
"prop": "liutongsuixingdan",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "发货产品",
"prop": "fahuochanpin",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "标准核算价",
"prop": "biaozhunhesuanjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "建议零售价",
"prop": "jianyilingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最近一次采购价",
"prop": "zuijinyicicaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最近一次销售价",
"prop": "zuijinyicixiaoshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱条形码",
"prop": "xiangtiaoxingma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装条码",
"prop": "zuidaxiangzhuangtiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "接口编码1",
"prop": "jiekoubianma1",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "接口编码2",
"prop": "jiekoubianma2",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "接口编码3",
"prop": "jiekoubianma3",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "发货产品基数",
"prop": "fahuochanpinjishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "采购最少数量",
"prop": "caigouzuishaoshuliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "采购倍数",
"prop": "caigoubeishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "采购滚动基数",
"prop": "caigougundongjishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最小单位产品",
"prop": "zuixiaodanweichanpin",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最小单位倍数",
"prop": "zuixiaodanweibeishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "产品归类",
"prop": "chanpinguilei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "产品归类II",
"prop": "chanpinguilei2",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位最高采购价",
"prop": "xiangdanweizuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位商超价1",
"prop": "xiangdanweishangchaojia1",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位现金价",
"prop": "xiangdanweixianjinjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位二批流通价",
"prop": "xiangdanweierpiliutongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位商超价",
"prop": "xiangdanweishangchaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位现金零售价",
"prop": "xiangdanweixianjinlingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位商超零售价",
"prop": "xiangdanweishangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位特通价",
"prop": "xiangdanweitetongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位分公司价",
"prop": "xiangdanweifengongsijia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位零食店价",
"prop": "xiangdanweilingshidianjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位初中高中价",
"prop": "xiangdanweichuzhonggaozhongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位车销价",
"prop": "xiangdanweichexiaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位发货价11",
"prop": "xiangdanweifahuojia11",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位发货价12",
"prop": "xiangdanweifahuojia12",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位最高采购价",
"prop": "zuidadanweizuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位商超价1",
"prop": "zuidadanweishangchaojia1",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位现金价",
"prop": "zuidadanweixianjinjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位二批流通价",
"prop": "zuidadanweierpiliutongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位商超价",
"prop": "zuidadanweishangchaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位现金零售价",
"prop": "zuidadanweixianjinlingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位商超零售价",
"prop": "zuidadanweishangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位特通价",
"prop": "zuidadanweitetongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位分公司价",
"prop": "zuidadanweifengongsijia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位零食店价",
"prop": "zuidadanweilingshidianjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位初中高中价",
"prop": "zuidadanweichuzhonggaozhongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位车销价",
"prop": "zuidadanweichexiaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位发货价11",
"prop": "zuidadanweifahuojia11",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位发货价12",
"prop": "zuidadanweifahuojia12",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "默认单据单位",
"prop": "morendanjudanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "不封箱单位",
"prop": "bufengxiangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "仓库提成类别",
"prop": "cangkutichengleibie",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "强制批次管理",
"prop": "qiangzhipiciguanli",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "立库存放区域",
"prop": "likucunfangquyu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "建档日期",
"prop": "jiandangriqi",
"type": "date",
"tableShow": true,
"formShow": true
},
{
"label": "出货是否加工",
"prop": "chuhuoshifujiagong",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "保质期天数需大于",
"prop": "baozhiqitianshuxudayu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "单品重量误差",
"prop": "danpinzhongliangwucha",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单品重量误差百分比%",
"prop": "zuidazhongliangwuchabaifenbi",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱重量误差",
"prop": "zuidaxiangzhongliangwucha",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "价格调整时间",
"prop": "jiagediaozhengshijian",
"type": "date",
"tableShow": true,
"formShow": true
},
{
"label": "录入人",
"prop": "lururen",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "允收天数",
"prop": "yunshoutianshu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "强制序列号管理",
"prop": "qiangzhixuliehaoguanli",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "国标条形码",
"prop": "guobiaotiaoxingma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "长(cm)",
"prop": "chang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "宽(cm)",
"prop": "kuan",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "高(cm)",
"prop": "gao",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "每托盘件数",
"prop": "meituopanjianshu",
"type": "number",
"tableShow": true,
"formShow": true
}
]

180
api/app/public/dingdan.json

@ -0,0 +1,180 @@
[
{
"label": "创建时间",
"prop": "create_at",
"type": "date"
},
{
"label": "更新时间",
"prop": "update_at",
"type": "date"
},
{
"label": "客户编号",
"prop": "kehubianhao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "简称",
"prop": "username",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "客户名称",
"prop": "kehumingcheng",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "产品代码",
"prop": "chanpindaima",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "厂编",
"prop": "changbian",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "货号",
"prop": "huohao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "单据单位数量",
"prop": "danjudanweishuliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "条码",
"prop": "tiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最小单位条码",
"prop": "zuixiaodanweitiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "修改后销售数量",
"prop": "xiugaihouxiaoshoushuliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最高采购价",
"prop": "zuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱装量",
"prop": "xiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装量",
"prop": "zuidaxiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "规格型号",
"prop": "guigexinghao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "计量单位",
"prop": "jiliangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "箱条码",
"prop": "xiangtiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱条码",
"prop": "zuidaxiangtiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "条码",
"prop": "tiaoma",
"type": "text",
"formShow": true,
"tableShow": true
},
{
"label": "品名",
"prop": "pinming",
"type": "select",
"formShow": true,
"tableShow": true
},
{
"label": "品名选项",
"prop": "pinmingxuanxiang",
"type": "textoption",
"formShow": false,
"tableShow": false
},
{
"label": "单位",
"prop": "danwei",
"type": "text",
"formShow": true,
"tableShow": true
},
{
"label": "规格",
"prop": "guige",
"type": "text",
"formShow": true,
"tableShow": true
},
{
"label": "销售数量",
"prop": "xiaoshoushuliang",
"type": "number",
"formShow": true,
"tableShow": true
},
{
"label": "销售金额",
"prop": "xiaoshoujine",
"type": "number",
"formShow": true,
"tableShow": true
}
]

40
api/app/public/user.json

@ -0,0 +1,40 @@
[
{
"label": "创建时间",
"prop": "create_at",
"type": "date"
},
{
"label": "更新时间",
"prop": "update_at",
"type": "date"
},
{
"label": "客户编号",
"prop": "usercode",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "简称",
"prop": "username",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "业务员",
"prop": "salesman",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "地址",
"prop": "address",
"type": "text",
"tableShow": true,
"formShow": true
}
]

11
api/app/router.js

@ -0,0 +1,11 @@
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.post('/api/userInfo', controller.user.index);
router.post('/api/chanpinInfo', controller.chanpin.index);
router.post('/api/dingdanInfo', controller.dingdan.index);
router.post('/api/exportDingdanInfo', controller.exportData.index);
};

67
api/app/service/chanpin.js

@ -0,0 +1,67 @@
'use strict';
const Service = require('egg').Service;
const _ = require("lodash")
class ChanpinService extends Service {
async index(params) {
let { ctx } = this
let modelLocal = ctx.model.Chanpin
let returnData = { hasError: false, msg: "数据错误", list: [] }
//新增
let subType = params.subType
let returnComponent = params.returnData || []
let paramsLocal = _.omit(params, ["subType", "returnData", "url"])
if (subType === "add") {
paramsLocal = paramsLocal.list[0]
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.create(paramsLocal)
returnData.hasError = false
returnData.msg = "数据新增成功"
} else if (subType === "multi") {
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.insertMany(paramsLocal.list)
returnData.hasError = false
returnData.msg = "批量新增成功"
} else if (subType === "del") {
let res = await modelLocal.updateMany({ _id: { $in: paramsLocal.ids } }, { isExit: 0, update_at: Date.now() })
returnData.hasError = false
returnData.msg = "数据删除成功"
} else if (subType === "edit") {
paramsLocal = paramsLocal.list[0]
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.updateOne({ _id: paramsLocal._id }, paramsLocal)
returnData.hasError = false
returnData.msg = "数据更新成功"
} else if (subType === "get") {
let pageSize = paramsLocal.pageSize
let currentPage = paramsLocal.currentPage
let paramsLocalInfo = _.omit(paramsLocal, ["pageSize", "currentPage", "url"])
let paramsLocalInfoNotDel = { ...paramsLocalInfo, isExit: 1 }
let res = await modelLocal.find(paramsLocalInfoNotDel).sort({ update_at: -1 }).skip((currentPage - 1) * pageSize).limit(pageSize)
let resData = [];
for (let i = 0; i < res.length; i++) {
let elei = res[i];
let resObj = { _id: elei._id }
if (returnComponent.length) {
for (let j = 0; j < returnComponent.length; j++) {
let elej = returnComponent[j];
resObj[elej] = elei[elej]
}
} else {
resObj = elei
}
resData.push(resObj)
}
returnData.hasError = false
returnData.msg = "查询成功"
returnData.list = resData
}
let allParamsLocalInfo = _.omit(paramsLocal, ["pageSize", "currentPage", "url", "list", "update_at"])
let allParamsLocalInfoNotDel = { ...allParamsLocalInfo, isExit: 1 }
let count = await modelLocal.find(allParamsLocalInfoNotDel).count()
returnData["count"] = count
return returnData
}
}
module.exports = ChanpinService;

191
api/app/service/dingdan.js

@ -0,0 +1,191 @@
'use strict';
const Service = require('egg').Service;
const _ = require("lodash");
class DingdanService extends Service {
async index(params) {
let { ctx } = this
let modelLocal = ctx.model.Dingdan
let chanpinModel = ctx.model.Chanpin
let returnData = { hasError: false, msg: "数据错误", list: [] }
//新增
let subType = params.subType
let returnComponent = params.returnData || []
let paramsLocal = _.omit(params, ["subType", "returnData", "url"])
if (subType === "add") {
paramsLocal = paramsLocal.list[0]
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.create(paramsLocal)
returnData.hasError = false
returnData.msg = "数据新增成功"
} else if (subType === "multi") {
paramsLocal["update_at"] = Date.now();
let list = await this.dealList(paramsLocal.list)
let res = await modelLocal.insertMany(list)
returnData.hasError = false
returnData.msg = "批量新增成功"
} else if (subType === "del") {
await modelLocal.updateMany({ _id: { $in: paramsLocal.ids } }, { isExit: 0, update_at: Date.now() })
returnData.hasError = false
returnData.msg = "数据删除成功"
} else if (subType === "edit") {
paramsLocal = paramsLocal.list[0]
paramsLocal["update_at"] = Date.now();
let chanpinItemA = await chanpinModel.find({ tiaoxingma: paramsLocal.tiaoma })
let chanpinItemB = await chanpinModel.find({ xiangtiaoxingma: paramsLocal.tiaoma })
let chanpinItemC = await chanpinModel.find({ zuidaxiangzhuangtiaoma: paramsLocal.tiaoma })
if (chanpinItemA.length || chanpinItemB.length || chanpinItemC.length) {
paramsLocal = { ...paramsLocal, isNotSale: false }
let res = await modelLocal.updateOne({ _id: paramsLocal._id }, paramsLocal)
returnData.hasError = false
returnData.msg = "数据更新成功"
} else {
returnData.hasError = true
returnData.msg = "数据更新失败,请检查产品条形码是否填写正确"
}
} else if (subType === "get") {
let pageSize = paramsLocal.pageSize
let currentPage = paramsLocal.currentPage
let paramsLocalInfo = _.omit(paramsLocal, ["pageSize", "currentPage", "url"])
let paramsLocalInfoNotDel = { ...paramsLocalInfo, isExit: 1 }
let res = await modelLocal.find(paramsLocalInfoNotDel).sort({ update_at: -1 }).skip((currentPage - 1) * pageSize).limit(pageSize)
let resData = [];
for (let i = 0; i < res.length; i++) {
let elei = res[i];
let resObj = { _id: elei._id }
if (returnComponent.length) {
for (let j = 0; j < returnComponent.length; j++) {
let elej = returnComponent[j];
resObj[elej] = elei[elej]
}
} else {
resObj = elei
}
resData.push(resObj)
}
returnData.hasError = false
returnData.msg = "查询成功"
returnData.list = resData
}
let allParamsLocalInfo = _.omit(paramsLocal, ["pageSize", "currentPage", "url"])
let allParamsLocalInfoNotDel = { ...allParamsLocalInfo, isExit: 1 }
let count = await modelLocal.find(allParamsLocalInfoNotDel).count()
returnData["count"] = count
return returnData
}
async dealList(list) {
let { ctx } = this
let listLocal = []
let listCopy = _.cloneDeep(list)
let pinmingGroup = _.groupBy(listCopy, o => o.tiaoma)
let pinmingOptionObj = {}
for (let key in pinmingGroup) {
let value = pinmingGroup[key]
let pinmingxuxnaing = []
for (let i = 0; i < value.length; i++) {
let pinmingOptionItem = {}
let element = value[i];
pinmingOptionItem["key"] = element.pinming
pinmingOptionItem["value"] = element.pinming
pinmingxuxnaing.push(pinmingOptionItem)
}
pinmingOptionObj[key] = pinmingxuxnaing
}
let userModel = ctx.model.User
let chanpinModel = ctx.model.Chanpin
for (let i = 0; i < list.length; i++) {
let item = _.cloneDeep(list[i]);
item["huohao"] = item.tiaoma
item["pinmingxuanxiang"] = pinmingOptionObj[item.tiaoma]
item["danjudanweishuliang"] = item.xiaoshoushuliang
let userItem = await userModel.find({ usercode: item.kehubianhao })
let chanpinItemA = await chanpinModel.find({ tiaoxingma: item.tiaoma })
let chanpinItemB = await chanpinModel.find({ xiangtiaoxingma: item.tiaoma })
let chanpinItemC = await chanpinModel.find({ zuidaxiangzhuangtiaoma: item.tiaoma })
if (userItem.length) {
item["kehubianhao"] = _.get(userItem, [0, "usercode"], "")
item["username"] = _.get(userItem, [0, "username"], "")
} else {
item["kehubianhao"] = ""
item["username"] = ""
}
if (chanpinItemA.length) {
item["changbian"] = _.get(chanpinItemA, [0, "daima"], "")
item["chanpindaima"] = _.get(chanpinItemA, [0, "daima"], "")
item["zuixiaodanweitiaoma"] = _.get(chanpinItemA, [0, "tiaoxingma"], "")
item["xiaoshoushuliang"] = item.xiaoshoushuliang
item.isNotSale = false
let guigexinghao = _.get(chanpinItemA, [0, "guigexinghao"], "")
let guigexinghaoArr = _.split(guigexinghao, "*")
let jishu = Number(guigexinghaoArr[1])
if (item.xiaoshoushuliang > jishu) {
let count = Math.floor(item.xiaoshoushuliang / jishu)
item["xiugaihouxiaoshoushuliang"] = count * jishu
} else {
item["xiugaihouxiaoshoushuliang"] = item.xiaoshoushuliang
}
item["xiaoshoujine"] = item.xiaoshoujine
item["zuigaocaigoujia"] = _.get(chanpinItemA, [0, "zuigaocaigoujia"], "")
item["xiangzhuangliang"] = _.get(chanpinItemA, [0, "xiangzhuangliang"], "")
item["zuidaxiangzhuangliang"] = _.get(chanpinItemA, [0, "zuidadanweixiangzhuangliang"], "")
item["guigexinghao"] = _.get(chanpinItemA, [0, "guigexinghao"], "")
item["jiliangdanwei"] = _.get(chanpinItemA, [0, "jiliangdanwei"], "")
item["xiangtiaoma"] = _.get(chanpinItemA, [0, "xiangtiaoxingma"], "")
item["zuidaxiangtiaoma"] = _.get(chanpinItemA, [0, "zuidaxiangzhuangtiaoma"], "")
} else if (chanpinItemB.length) {
item["changbian"] = _.get(chanpinItemB, [0, "daima"], "")
item["chanpindaima"] = _.get(chanpinItemB, [0, "daima"], "")
item["zuixiaodanweitiaoma"] = _.get(chanpinItemB, [0, "tiaoxingma"], "")
item["xiaoshoushuliang"] = item.xiaoshoushuliang
let guigexinghao = _.get(chanpinItemB, [0, "guigexinghao"], "")
let guigexinghaoArr = _.split(guigexinghao, "*")
let jishu = Number(guigexinghaoArr[1])
item["xiugaihouxiaoshoushuliang"] = item.xiaoshoushuliang * jishu
item["xiaoshoujine"] = item.xiaoshoujine
item["zuigaocaigoujia"] = _.get(chanpinItemB, [0, "zuigaocaigoujia"], "")
item["xiangzhuangliang"] = _.get(chanpinItemB, [0, "xiangzhuangliang"], "")
item["zuidaxiangzhuangliang"] = _.get(chanpinItemB, [0, "zuidadanweixiangzhuangliang"], "")
item["guigexinghao"] = _.get(chanpinItemB, [0, "guigexinghao"], "")
item["jiliangdanwei"] = _.get(chanpinItemB, [0, "jiliangdanwei"], "")
item["xiangtiaoma"] = _.get(chanpinItemB, [0, "xiangtiaoxingma"], "")
item["zuidaxiangtiaoma"] = _.get(chanpinItemB, [0, "zuidaxiangzhuangtiaoma"], "")
} else if (chanpinItemC.length) {
item["changbian"] = _.get(chanpinItemC, [0, "daima"], "")
item["chanpindaima"] = _.get(chanpinItemC, [0, "daima"], "")
item["zuixiaodanweitiaoma"] = _.get(chanpinItemC, [0, "tiaoxingma"], "")
item["xiaoshoushuliang"] = item.xiaoshoushuliang
let guigexinghao = _.get(chanpinItemC, [0, "guigexinghao"], "")
let guigexinghaoArr = _.split(guigexinghao, "*")
let jishu = Number(guigexinghaoArr[1])
item["xiugaihouxiaoshoushuliang"] = item.xiaoshoushuliang * jishu * Number((_.get(chanpinItemC, [0, "xiangzhuangliang"], 1) || 1))
item["xiaoshoujine"] = item.xiaoshoujine
item["zuigaocaigoujia"] = _.get(chanpinItemC, [0, "zuigaocaigoujia"], "")
item["xiangzhuangliang"] = _.get(chanpinItemC, [0, "xiangzhuangliang"], "")
item["zuidaxiangzhuangliang"] = _.get(chanpinItemC, [0, "zuidadanweixiangzhuangliang"], "")
item["guigexinghao"] = _.get(chanpinItemC, [0, "guigexinghao"], "")
item["jiliangdanwei"] = _.get(chanpinItemC, [0, "jiliangdanwei"], "")
item["xiangtiaoma"] = _.get(chanpinItemC, [0, "xiangtiaoxingma"], "")
item["zuidaxiangtiaoma"] = _.get(chanpinItemC, [0, "zuidaxiangzhuangtiaoma"], "")
} else {
item["changbian"] = ""
item["chanpindaima"] = ""
item["zuixiaodanweitiaoma"] = ""
item["xiaoshoushuliang"] = item.xiaoshoushuliang
item["xiugaihouxiaoshoushuliang"] = item.xiaoshoushuliang
item["xiaoshoujine"] = item.xiaoshoujine
item["zuigaocaigoujia"] = ""
item["xiangzhuangliang"] = ""
item["zuidaxiangzhuangliang"] = ""
item["guigexinghao"] = ""
item["jiliangdanwei"] = ""
item["xiangtiaoma"] = ""
item["zuidaxiangtiaoma"] = ""
item.isNotSale = true
}
listLocal.push(item)
}
return listLocal
}
}
module.exports = DingdanService;

23
api/app/service/exportData.js

@ -0,0 +1,23 @@
'use strict';
const Service = require('egg').Service;
const _ = require("lodash");
class ExportDataService extends Service {
async index(params) {
let { ctx } = this
let modelLocal = ctx.model[params.model]
let subType = params.subType
let paramsLocal = _.omit(params, ["subType", "url", "model"])
let msgObj = {
exportS6: "成功导出S6订单",
exportxiaoshou: "成功导出销售订单",
}
let ParamsLocalNotDel = { ...paramsLocal, isExit: 1 }
let res = await modelLocal.find(ParamsLocalNotDel).sort({ update_at: -1 })
let count = await modelLocal.find(ParamsLocalNotDel).count()
let returnData = { hasError: false, msg: msgObj[subType], subType, list: res, count }
return returnData
}
}
module.exports = ExportDataService;

67
api/app/service/user.js

@ -0,0 +1,67 @@
'use strict';
const Service = require('egg').Service;
const _ = require("lodash")
class UserService extends Service {
async index(params) {
let { ctx } = this
let modelLocal = ctx.model.User
let returnData = { hasError: false, msg: "数据错误", list: [] }
//新增
let subType = params.subType
let returnComponent = params.returnData || []
let paramsLocal = _.omit(params, ["subType", "returnData", "url"])
if (subType === "add") {
paramsLocal = paramsLocal.list[0]
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.create(paramsLocal)
returnData.hasError = false
returnData.msg = "数据新增成功"
} else if (subType === "multi") {
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.insertMany(paramsLocal.list)
returnData.hasError = false
returnData.msg = "批量新增成功"
} else if (subType === "del") {
let res = await modelLocal.updateMany({ _id: { $in: paramsLocal.ids } }, { isExit: 0, update_at: Date.now() })
returnData.hasError = false
returnData.msg = "数据删除成功"
} else if (subType === "edit") {
paramsLocal = paramsLocal.list[0]
paramsLocal["update_at"] = Date.now();
let res = await modelLocal.updateOne({ _id: paramsLocal._id }, paramsLocal)
returnData.hasError = false
returnData.msg = "数据更新成功"
} else if (subType === "get") {
let pageSize = paramsLocal.pageSize
let currentPage = paramsLocal.currentPage
let paramsLocalInfo = _.omit(paramsLocal, ["pageSize", "currentPage", "url"])
let paramsLocalInfoNotDel = { ...paramsLocalInfo, isExit: 1 }
let res = await modelLocal.find(paramsLocalInfoNotDel).sort({ update_at: -1 }).skip((currentPage - 1) * pageSize).limit(pageSize)
let resData = [];
for (let i = 0; i < res.length; i++) {
let elei = res[i];
let resObj = { _id: elei._id }
if (returnComponent.length) {
for (let j = 0; j < returnComponent.length; j++) {
let elej = returnComponent[j];
resObj[elej] = elei[elej]
}
} else {
resObj = elei
}
resData.push(resObj)
}
returnData.hasError = false
returnData.msg = "查询成功"
returnData.list = resData
}
let allParamsLocalInfo = _.omit(paramsLocal, ["pageSize", "currentPage", "url"])
let allParamsLocalInfoNotDel = { ...allParamsLocalInfo, isExit: 1 }
let count = await modelLocal.find(allParamsLocalInfoNotDel).count()
returnData["count"] = count
return returnData
}
}
module.exports = UserService;

58
api/config/config.default.js

@ -0,0 +1,58 @@
/* eslint valid-jsdoc: "off" */
/**
* @param {Egg.EggAppInfo} appInfo app info
*/
module.exports = appInfo => {
/**
* built-in config
* @type {Egg.EggAppConfig}
**/
const config = exports = {};
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1718796622177_8852';
// add your middleware config here
config.middleware = [];
config.mongoose = {
client: {
url: 'mongodb://127.0.0.1:27018/back',
options: {
// useNewUrlParser: true,
// useUnifiedTopology: true
}
}
}
config.security = {
csrf: {
// 判断是否需要 ignore 的方法,请求上下文 context 作为第一个参数
// ignore: ctx => isInnerIp(ctx.ip),
ignore: '/',
},
};
config.cors = {
// 任何地址都可以访问
origin: "*",
// 指定地址才可以访问
// origin: 'http://localhost:8080',
// allowMethods: 'GET,PUT,POST,DELETE',
allowMethods: 'POST',
// cookie跨域配置
credentials: true
};
config.bodyParser = {
formLimit: "100mb",
jsonLimit: "100mb",
textLimit: "100mb",
}
// add your user config here
const userConfig = {
// myAppName: 'egg',
};
return {
...config,
...userConfig,
};
};

11
api/config/plugin.js

@ -0,0 +1,11 @@
/** @type Egg.EggPlugin */
module.exports = {
// had enabled by egg
// static: {
// enable: true,
// }
mongoose: {
enable: true,
package: 'egg-mongoose',
},
};

5
api/jsconfig.json

@ -0,0 +1,5 @@
{
"include": [
"**/*"
]
}

40
api/package.json

@ -0,0 +1,40 @@
{
"name": "back",
"version": "1.0.0",
"description": "back",
"private": true,
"egg": {
"declarations": true
},
"dependencies": {
"egg": "^3.17.5",
"egg-mongoose": "^4.0.1",
"egg-scripts": "2",
"lodash": "^4.17.21"
},
"devDependencies": {
"egg-bin": "6",
"egg-mock": "5",
"eslint": "8",
"eslint-config-egg": "13"
},
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"start": "egg-scripts start --daemon --title=egg-server-back",
"stop": "egg-scripts stop --title=egg-server-back",
"dev": "egg-bin dev",
"test": "npm run lint -- --fix && npm run test:local",
"test:local": "egg-bin test",
"cov": "egg-bin cov",
"lint": "eslint .",
"ci": "npm run lint && npm run cov"
},
"repository": {
"type": "git",
"url": ""
},
"author": "lichong",
"license": "MIT"
}

23
api/test/app/controller/home.test.js

@ -0,0 +1,23 @@
const { strict: assert } = require('node:assert');
const path = require('node:path');
const { statSync } = require('node:fs');
const { app } = require('egg-mock/bootstrap');
describe('test/app/controller/home.test.js', () => {
it('should assert', async () => {
const pkg = require('../../../package.json');
assert(app.config.keys.startsWith(pkg.name));
});
it('should typings exists', async () => {
const typings = path.join(__dirname, '../../../typings');
assert(statSync(typings));
});
it('should GET /', async () => {
return app.httpRequest()
.get('/')
.expect('hi, egg')
.expect(200);
});
});

9
front/.editorconfig

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

4
front/.gitignore

@ -0,0 +1,4 @@
node_modules
dist
out
*.log*

1
front/.npmrc

@ -0,0 +1 @@
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/

6
front/.prettierignore

@ -0,0 +1,6 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json

6
front/.prettierrc

@ -0,0 +1,6 @@
{
"singleQuote": true,
"semi": false,
"printWidth": 100,
"trailingComma": "none"
}

34
front/README.md

@ -0,0 +1,34 @@
# my-app
An Electron application with Vue
## Recommended IDE Setup
- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
## Project Setup
### Install(node 16.20.1)
```bash
$ npm install
```
### Development
```bash
$ npm run dev
```
### Build
```bash
# For windows
$ npm run build:win
# For macOS
$ npm run build:mac
# For Linux
$ npm run build:linux
```

12
front/build/entitlements.mac.plist

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>

BIN
front/build/icon.icns

Binary file not shown.

BIN
front/build/icon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

36
front/build/notarize.js

@ -0,0 +1,36 @@
const { notarize } = require('electron-notarize')
module.exports = async (context) => {
if (process.platform !== 'darwin') return
console.log('aftersign hook triggered, start to notarize app.')
if (!process.env.CI) {
console.log(`skipping notarizing, not in CI.`)
return
}
if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) {
console.warn('skipping notarizing, APPLE_ID and APPLE_ID_PASS env variables must be set.')
return
}
const appId = 'com.electron.app'
const { appOutDir } = context
const appName = context.packager.appInfo.productFilename
try {
await notarize({
appBundleId: appId,
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLEIDPASS
})
} catch (error) {
console.error(error)
}
console.log(`done notarizing ${appId}.`)
}

43
front/electron-builder.yml

@ -0,0 +1,43 @@
appId: com.electron.lichong
productName: 时光机
directories:
buildResources: build
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
asarUnpack:
- '**/*.{node,dll}'
afterSign: build/notarize.js
win:
executableName: lichong-app
nsis:
oneClick: false
artifactName: ${name}-${version}-setup.${ext}
allowToChangeInstallationDirectory: true
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://example.com/auto-updates

28
front/electron.vite.config.js

@ -0,0 +1,28 @@
import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()]
},
preload: {
plugins: [externalizeDepsPlugin()],
build: {
rollupOptions: {
input: {
dl: resolve(__dirname, 'src/preload/dl.js'),
index: resolve(__dirname, 'src/preload/index.js')
}
}
}
},
renderer: {
resolve: {
alias: {
'@renderer': resolve('src/renderer/src')
}
},
plugins: [vue()]
}
})

6
front/jsconfig.json

@ -0,0 +1,6 @@
{
"exclude": [
"node_modules",
"public"
]
}

6161
front/package-lock.json

File diff suppressed because it is too large

41
front/package.json

@ -0,0 +1,41 @@
{
"name": "electron",
"version": "1.0.0",
"description": "An Electron application with Vue",
"main": "./out/main/index.js",
"author": "lichong",
"homepage": "https://www.electronjs.org",
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"build": "electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:win": "npm run build && electron-builder --win --config",
"build:mac": "npm run build && electron-builder --mac --config",
"build:linux": "npm run build && electron-builder --linux --config"
},
"dependencies": {
"@electron-toolkit/preload": "^1.0.2",
"@electron-toolkit/utils": "^1.0.2",
"axios": "^1.6.8",
"dayjs": "^1.11.11",
"element-plus": "^2.7.1",
"lodash": "^4.17.21",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@vitejs/plugin-vue": "^3.1.2",
"@vue/eslint-config-prettier": "^7.0.0",
"electron": "^20.3.2",
"electron-builder": "^23.6.0",
"electron-notarize": "^1.2.1",
"electron-vite": "^1.0.11",
"less": "^4.1.3",
"prettier": "^2.7.1",
"vite": "^3.1.8",
"vue": "^3.2.41"
}
}

BIN
front/public/icon/icon.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

78
front/src/main/index.js

@ -0,0 +1,78 @@
import { app, shell, BrowserWindow, nativeImage, ipcMain } from 'electron'
import * as path from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import axios from 'axios'
// logo
const logoIcon = nativeImage.createFromPath(path.join(__dirname, '../../public/icon/icon.jpg'))
// 主窗口
let mainWindow
function createWindow() {
mainWindow = new BrowserWindow({
// fullscreen: true,
// fullscreenable: true,
width: 960,
height: 540,
// width:1080,
// height:1920,
show: false,
autoHideMenuBar: true,
icon: logoIcon,
webPreferences: {
preload: path.resolve(__dirname, '../preload/index.js'),
sandbox: false,
}
})
mainWindow.on('ready-to-show', () => {
mainWindow.show()
// mainWindow.webContents.openDevTools()
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
// mainWindow.loadURL('http://localhost:5173/')
mainWindow.on('close', () => {
app.exit()
})
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
}
}
app.whenReady().then(() => {
electronApp.setAppUserModelId('com.electron')
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
ipcMain.on('sendMessage', async (eve, params) => {
let res = await axios.post(`http://127.0.0.1:7001${params.url}`, params)
mainWindow.webContents.send(`${params.url.split("/")[2]}`, res.data)
})
ipcMain.on('exportData', async (eve, params) => {
let res = await axios.post(`http://127.0.0.1:7001${params.url}`, params)
mainWindow.webContents.send(`${params.model}`, res.data)
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.

21
front/src/preload/dl.js

@ -0,0 +1,21 @@
import { contextBridge, clipboard } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
// Custom APIs for renderer
const api = {}
// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
contextBridge.exposeInMainWorld('elecClipboard', clipboard)
} catch (error) {
console.error(error)
}
} else {
window.electron = electronAPI
window.api = api
}

21
front/src/preload/index.js

@ -0,0 +1,21 @@
import { contextBridge, clipboard } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
// Custom APIs for renderer
const api = {}
// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
contextBridge.exposeInMainWorld('elecClipboard', clipboard)
} catch (error) {
console.error(error)
}
} else {
window.electron = electronAPI
window.api = api
}

18
front/src/renderer/index.html

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>产品处理</title>
<!-- <link rel="icon" href="/icon/icon.jpg" /> -->
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self';img-src 'self' data:; style-src 'self' 'unsafe-inline'"
/>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

84
front/src/renderer/src/App.vue

@ -0,0 +1,84 @@
<template>
<div class="appClass" v-if="isVip">
<el-tabs tab-position="left" class="appClass" @tab-change="tabChange" v-model="tabName">
<el-tab-pane label="客户信息" name="user">
<!-- todo -->
<user ref="user"></user>
</el-tab-pane>
<el-tab-pane label="产品信息" name="chanpin">
<chanpin ref="chanpin">
</chanpin>
</el-tab-pane>
<el-tab-pane label="订单信息" name="dingdan">
<dingdan ref="dingdan"></dingdan>
</el-tab-pane>
</el-tabs>
</div>
<div v-else class="noVip">
<h3>
<el-tag type="danger" class="noVipTag">体验已过期请联系管理员</el-tag>
</h3>
</div>
</template>
<script>
import _ from 'lodash'
import dayjs from 'dayjs'
import user from "./views/user.vue"
import chanpin from "./views/chanpin.vue"
import dingdan from "./views/dingdan.vue"
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'app',
components: { user, chanpin, dingdan },
data() {
return {
_: _,
isVip: false,
tabName: "user",
}
},
methods: {
tabChange(name) {
this.$refs[name].searchData()
},
},
async mounted() {
let fiveDay = dayjs('2024-06-29T00:00:00').valueOf()
if (!this.isVip) {
if (dayjs().valueOf() > fiveDay) {
this.isVip = false
return
} else {
this.isVip = true
}
}
},
watch: {},
computed: {}
}
</script>
<style scoped>
.appClass {
width: 100vw;
height: 100vh;
position: relative;
}
.menuClass {
border-right: 0;
height: 100%;
}
.noVip {
text-align: center;
margin-top: calc(50vh - 48px);
}
.noVipTag {
font-size: 48px;
line-height: 48px;
padding: 36px;
}
</style>

20
front/src/renderer/src/assets/css/base.css

@ -0,0 +1,20 @@
html,
body {
margin: 0;
padding: 0;
}
.el-table .cell {
padding: 0 !important;
}
.el-table .isNotSale {
background-color: #a0cfff;
}
.el-table .redRow {
background-color: #fab6b6;
}
.el-table .yellowRow {
background-color: #f3d19e;
}

810
front/src/renderer/src/assets/json/chanpin.json

@ -0,0 +1,810 @@
[
{
"label": "创建时间",
"prop": "create_at",
"type": "date"
},
{
"label": "更新时间",
"prop": "update_at",
"type": "date"
},
{
"label": "代码",
"prop": "daima",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "品名",
"prop": "pinming",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "规格型号",
"prop": "guigexinghao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "助记符",
"prop": "zhujifu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "计量单位",
"prop": "jiliangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "条形码",
"prop": "tiaoxingma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "箱装量",
"prop": "xiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱装单位",
"prop": "xiangzhuangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装量",
"prop": "zuidadanweixiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装单位",
"prop": "zuidaxiangzhuangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "产地",
"prop": "chandi",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "主供应商",
"prop": "zhugongyingshang",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "经销商",
"prop": "jingxiaoshang",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "所属类别",
"prop": "suoshuleibie",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最高采购价",
"prop": "zuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "商超价1",
"prop": "shangchaojia1",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "现金价",
"prop": "xianjinjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "二批流通价",
"prop": "erpiliutongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "商超价",
"prop": "shangchaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "现金零售价",
"prop": "xianjinlingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "商超零售价",
"prop": "shangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "特通价",
"prop": "tetongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "分公司价",
"prop": "fengongsijia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "零食店价",
"prop": "shangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "初中高中价",
"prop": "chuzhonggaozhongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "车销价",
"prop": "chexiaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "发货价11",
"prop": "fahuojia11",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "发货价12",
"prop": "fahuojia12",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "进销税税率%",
"prop": "jinxiaoshuilv",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "发货税税率%",
"prop": "fahuoshuilv",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "包装",
"prop": "baozhuang",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "毛利率",
"prop": "maolilv",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "主存放仓库",
"prop": "zhucunfangcangku",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "有保质期",
"prop": "youbaozhiqi",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "保质期(天)",
"prop": "baozhiqi",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "有效",
"prop": "youxiao",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "采销类型",
"prop": "caixiaoleixing",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "商品类型",
"prop": "shangpinleixing",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "备注",
"prop": "beizhu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "单位重量",
"prop": "danweizhongliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "品牌",
"prop": "pinpai",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "单位体积(立方米)",
"prop": "danweitiji",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱重量(kg)",
"prop": "xiangzhongliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位重量(kg)",
"prop": "zuidadanweizhongliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱体积(立方米)",
"prop": "xiangtiji",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "描述",
"prop": "miaoshu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "仓库出入库时,以‘箱装单位’为依准",
"prop": "yixiangzhuangdanweiweiyizhun",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "打印‘流通随行单’",
"prop": "liutongsuixingdan",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "发货产品",
"prop": "fahuochanpin",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "标准核算价",
"prop": "biaozhunhesuanjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "建议零售价",
"prop": "jianyilingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最近一次采购价",
"prop": "zuijinyicicaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最近一次销售价",
"prop": "zuijinyicixiaoshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱条形码",
"prop": "xiangtiaoxingma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱装条码",
"prop": "zuidaxiangzhuangtiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "接口编码1",
"prop": "jiekoubianma1",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "接口编码2",
"prop": "jiekoubianma2",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "接口编码3",
"prop": "jiekoubianma3",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "发货产品基数",
"prop": "fahuochanpinjishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "采购最少数量",
"prop": "caigouzuishaoshuliang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "采购倍数",
"prop": "caigoubeishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "采购滚动基数",
"prop": "caigougundongjishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最小单位产品",
"prop": "zuixiaodanweichanpin",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最小单位倍数",
"prop": "zuixiaodanweibeishu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "产品归类",
"prop": "chanpinguilei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "产品归类II",
"prop": "chanpinguilei2",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位最高采购价",
"prop": "xiangdanweizuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位商超价1",
"prop": "xiangdanweishangchaojia1",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位现金价",
"prop": "xiangdanweixianjinjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位二批流通价",
"prop": "xiangdanweierpiliutongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位商超价",
"prop": "xiangdanweishangchaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位现金零售价",
"prop": "xiangdanweixianjinlingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位商超零售价",
"prop": "xiangdanweishangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位特通价",
"prop": "xiangdanweitetongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位分公司价",
"prop": "xiangdanweifengongsijia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位零食店价",
"prop": "xiangdanweilingshidianjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位初中高中价",
"prop": "xiangdanweichuzhonggaozhongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位车销价",
"prop": "xiangdanweichexiaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位发货价11",
"prop": "xiangdanweifahuojia11",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "箱单位发货价12",
"prop": "xiangdanweifahuojia12",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位最高采购价",
"prop": "zuidadanweizuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位商超价1",
"prop": "zuidadanweishangchaojia1",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位现金价",
"prop": "zuidadanweixianjinjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位二批流通价",
"prop": "zuidadanweierpiliutongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位商超价",
"prop": "zuidadanweishangchaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位现金零售价",
"prop": "zuidadanweixianjinlingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位商超零售价",
"prop": "zuidadanweishangchaolingshoujia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位特通价",
"prop": "zuidadanweitetongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位分公司价",
"prop": "zuidadanweifengongsijia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位零食店价",
"prop": "zuidadanweilingshidianjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位初中高中价",
"prop": "zuidadanweichuzhonggaozhongjia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位车销价",
"prop": "zuidadanweichexiaojia",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位发货价11",
"prop": "zuidadanweifahuojia11",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单位发货价12",
"prop": "zuidadanweifahuojia12",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "默认单据单位",
"prop": "morendanjudanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "不封箱单位",
"prop": "bufengxiangdanwei",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "仓库提成类别",
"prop": "cangkutichengleibie",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "强制批次管理",
"prop": "qiangzhipiciguanli",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "立库存放区域",
"prop": "likucunfangquyu",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "建档日期",
"prop": "jiandangriqi",
"type": "date",
"tableShow": true,
"formShow": true
},
{
"label": "出货是否加工",
"prop": "chuhuoshifujiagong",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "保质期天数需大于",
"prop": "baozhiqitianshuxudayu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "单品重量误差",
"prop": "danpinzhongliangwucha",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大单品重量误差百分比%",
"prop": "zuidazhongliangwuchabaifenbi",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "最大箱重量误差",
"prop": "zuidaxiangzhongliangwucha",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "价格调整时间",
"prop": "jiagediaozhengshijian",
"type": "date",
"tableShow": true,
"formShow": true
},
{
"label": "录入人",
"prop": "lururen",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "允收天数",
"prop": "yunshoutianshu",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "强制序列号管理",
"prop": "qiangzhixuliehaoguanli",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "国标条形码",
"prop": "guobiaotiaoxingma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "长(cm)",
"prop": "chang",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "宽(cm)",
"prop": "kuan",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "高(cm)",
"prop": "gao",
"type": "number",
"tableShow": true,
"formShow": true
},
{
"label": "每托盘件数",
"prop": "meituopanjianshu",
"type": "number",
"tableShow": true,
"formShow": true
}
]

206
front/src/renderer/src/assets/json/dingdan.json

@ -0,0 +1,206 @@
[
{
"label": "创建时间",
"prop": "create_at",
"type": "date"
},
{
"label": "更新时间",
"prop": "update_at",
"type": "date"
},
{
"label": "客户编号",
"prop": "kehubianhao",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "简称",
"prop": "username",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "客户名称",
"prop": "kehumingcheng",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "产品代码",
"prop": "chanpindaima",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "厂编",
"prop": "changbian",
"type": "text",
"tableShow": true,
"formShow": true,
"exportS6": true
},
{
"label": "货号",
"prop": "huohao",
"type": "text",
"tableShow": true,
"formShow": true,
"exportS6": true
},
{
"label": "单据单位数量",
"prop": "danjudanweishuliang",
"type": "number",
"tableShow": true,
"formShow": true,
"exportS6": true
},
{
"label": "条码",
"prop": "tiaoma",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "最小单位条码",
"prop": "zuixiaodanweitiaoma",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "修改后销售数量",
"prop": "xiugaihouxiaoshoushuliang",
"type": "number",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "最高采购价",
"prop": "zuigaocaigoujia",
"type": "number",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "箱装量",
"prop": "xiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "最大箱装量",
"prop": "zuidaxiangzhuangliang",
"type": "number",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "规格型号",
"prop": "guigexinghao",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "计量单位",
"prop": "jiliangdanwei",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "箱条码",
"prop": "xiangtiaoma",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "最大箱条码",
"prop": "zuidaxiangtiaoma",
"type": "text",
"tableShow": true,
"formShow": true,
"exportxiaoshou": true
},
{
"label": "条码",
"prop": "tiaoma",
"type": "text",
"formShow": true,
"tableShow": true
},
{
"label": "品名",
"prop": "pinming",
"type": "select",
"formShow": true,
"tableShow": true,
"exportxiaoshou": true
},
{
"label": "品名选项",
"prop": "pinmingxuanxiang",
"type": "textoption",
"formShow": false,
"tableShow": false
},
{
"label": "单位",
"prop": "danwei",
"type": "text",
"formShow": true,
"tableShow": true
},
{
"label": "规格",
"prop": "guige",
"type": "text",
"formShow": true,
"tableShow": true
},
{
"label": "销售数量",
"prop": "xiaoshoushuliang",
"type": "number",
"formShow": true,
"tableShow": true,
"exportxiaoshou": true
},
{
"label": "销售金额",
"prop": "xiaoshoujine",
"type": "number",
"formShow": true,
"tableShow": true,
"exportxiaoshou": true
},
{
"label": "是否有售卖",
"prop": "isNotSale",
"type": "number",
"formShow": false,
"tableShow": true
}
]

40
front/src/renderer/src/assets/json/user.json

@ -0,0 +1,40 @@
[
{
"label": "创建时间",
"prop": "create_at",
"type": "date"
},
{
"label": "更新时间",
"prop": "update_at",
"type": "date"
},
{
"label": "客户编号",
"prop": "usercode",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "简称",
"prop": "username",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "业务员",
"prop": "salesman",
"type": "text",
"tableShow": true,
"formShow": true
},
{
"label": "地址",
"prop": "address",
"type": "text",
"tableShow": true,
"formShow": true
}
]

83
front/src/renderer/src/components/dingdanformcomponent.vue

@ -0,0 +1,83 @@
<template>
<div class="tableClass">
<el-form :model="formData" label-suffix="" inline :disabled="disabled">
<el-form-item :label="formItem.label" :key="formIndex" v-for="(formItem, formIndex) in formHeader">
<template v-if="formItem.type === 'text'">
<el-input v-model="formData[formItem.prop]" />
</template>
<template v-else-if="formItem.type === 'select'">
<el-select v-model="formData[formItem.prop]" :placeholder="`请选择${formItem.label}`" style="width: 240px" >
<el-option v-for="item in formData[formItem.prop + 'xuanxiang']" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</template>
<template v-else-if="formItem.type === 'number'">
<el-input-number v-model="formData[formItem.prop]">
<template #decrease-icon>
<el-icon>
<ArrowDown />
</el-icon>
</template>
<template #increase-icon>
<el-icon>
<ArrowUp />
</el-icon>
</template>
</el-input-number>
</template>
<template v-else-if="formItem.type === 'date'">
<el-date-picker v-model="formData[formItem.prop]" type="date" :placeholder="`请选择${formItem.label}`" />
<el-input />
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
import _ from 'lodash'
import dayjs from 'dayjs'
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'dingdanformcomponent',
components: {},
props: {
formHeader: {
type: Array,
default: () => {
return []
}
},
formData: {
type: Object,
default: () => {
return {}
}
},
disabled: {
type: Boolean,
default: () => {
return false
}
}
},
data() {
return {
_: _,
dayjs: dayjs,
}
},
methods: {},
async mounted() { },
watch: {},
computed: {}
}
</script>
<style scoped>
.tableClass {
text-align: left;
text-align-last: left;
}
</style>

136
front/src/renderer/src/components/dingdantablecomponent.vue

@ -0,0 +1,136 @@
<template>
<div class="tableClass">
<el-table :data="tableData" height="calc(100vh - 84px)" border @select="selectChange" @select-all="selectChange" fit
:row-key="getRowKeys" :row-class-name="getRowClassName">
<el-table-column type="selection" width="38" :reserve-selection="true" fixed="left">
</el-table-column>
<el-table-column type="index" width="38" :reserve-selection="true" fixed="left" label="序号">
</el-table-column>
<el-table-column v-for="(headerItem, headerIndex) in tableHeader" :label="headerItem.label" show-overflow-tooltip
:key="headerIndex" :min-width="`${headerItem.label.length * 15 + 8}px`">
<template #default="scope">
<template v-if="headerItem.type === 'text'">
<span>{{ scope.row[headerItem.prop] }}</span>
</template>
<template v-else-if="headerItem.type === 'date'">
<span>{{ scope.row[headerItem.prop] }}</span>
</template>
<template v-else-if="headerItem.type === 'number'">
<span>{{ scope.row[headerItem.prop] }}</span>
</template>
<template v-else>{{ scope.row[headerItem.prop] }}</template>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="145">
<template #default="scope">
<el-button type="primary" circle @click="optClick(scope.row, 'edit')">
<el-icon>
<Edit />
</el-icon>
</el-button>
<el-button type="info" circle @click="optClick(scope.row, 'info')">
<el-icon>
<InfoFilled />
</el-icon>
</el-button>
<el-button type="danger" circle @click="optClick(scope.row, 'del')">
<el-icon>
<Delete />
</el-icon>
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination style="margin:8px 0 0 0" v-model:current-page="currentPage" v-model:page-size="pageSize"
:total="total" @size-change="handleSizeChange" layout="total, sizes, prev, pager, next, jumper"
:page-sizes="pageSizes" @current-change="handleCurrentChange" @prev-click="handleCurrentChange"
@next-click="handleCurrentChange"></el-pagination>
</div>
</template>
<script>
import _ from 'lodash'
import dayjs from 'dayjs'
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'dingdantablecomponent',
components: {},
props: {
tableHeader: {
type: Array,
default: () => {
return []
}
},
tableData: {
type: Array,
default: () => {
return []
}
},
pageSizes: {
type: Array,
default: () => {
return [16, 50, 100, 200]
}
},
total: {
type: Number,
default: () => {
return 0
}
},
},
data() {
return {
_: _,
dayjs: dayjs,
currentPage: 1,
pageSize: 16,
}
},
methods: {
selectChange(selection) {
this.$emit("selectChange", selection)
},
handleSizeChange(pageSize) {
this.$emit("handleSizeChange", pageSize)
},
handleCurrentChange(currentPage) {
this.$emit("handleCurrentChange", currentPage)
},
optClick(row, type) {
this.$emit(type, row)
},
// key
getRowKeys(row) {
return row._id; //
},
//
getRowClassName({ row }) {
if (row.isNotSale) {
return 'isNotSale'
}
if (row.xiaoshoujine < row.zuigaocaigoujia) {
return 'redRow'
}
if ((row.pinmingxuanxiang || []).length > 1) {
return 'yellowRow'
}
return ''
},
},
async mounted() { },
watch: {},
computed: {}
}
</script>
<style scoped>
.tableClass {
text-align: center;
text-align-last: center;
}
</style>

77
front/src/renderer/src/components/formcomponent.vue

@ -0,0 +1,77 @@
<template>
<div class="tableClass">
<el-form :model="formData" label-suffix="" inline :disabled="disabled">
<el-form-item :label="formItem.label" :key="formIndex" v-for="(formItem, formIndex) in formHeader">
<template v-if="formItem.type === 'text'">
<el-input v-model="formData[formItem.prop]" />
</template>
<template v-else-if="formItem.type === 'number'">
<el-input-number v-model="formData[formItem.prop]">
<template #decrease-icon>
<el-icon>
<ArrowDown />
</el-icon>
</template>
<template #increase-icon>
<el-icon>
<ArrowUp />
</el-icon>
</template>
</el-input-number>
</template>
<template v-else-if="formItem.type === 'date'">
<el-date-picker v-model="formData[formItem.prop]" type="date" :placeholder="`请选择${formItem.label}`" />
<el-input />
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
import _ from 'lodash'
import dayjs from 'dayjs'
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'formcomponent',
components: {},
props: {
formHeader: {
type: Array,
default: () => {
return []
}
},
formData: {
type: Object,
default: () => {
return {}
}
},
disabled: {
type: Boolean,
default: () => {
return false
}
}
},
data() {
return {
_: _,
dayjs: dayjs,
}
},
methods: {},
async mounted() { },
watch: {},
computed: {}
}
</script>
<style scoped>
.tableClass {
text-align: left;
text-align-last: left;
}
</style>

120
front/src/renderer/src/components/tablecomponent.vue

@ -0,0 +1,120 @@
<template>
<div class="tableClass">
<el-table :data="tableData" height="calc(100vh - 84px)" border @select="selectChange" @select-all="selectChange" fit :row-key="getRowKeys">
<el-table-column type="selection" width="38" :reserve-selection="true" fixed="left">
</el-table-column>
<el-table-column type="index" width="38" :reserve-selection="true" fixed="left" label="序号">
</el-table-column>
<el-table-column v-for="(headerItem, headerIndex) in tableHeader" :label="headerItem.label" show-overflow-tooltip
:key="headerIndex" :min-width="`${headerItem.label.length*15+8}px`">
<template #default="scope">
<template v-if="headerItem.type === 'text'">
<span>{{ scope.row[headerItem.prop] }}</span>
</template>
<template v-else-if="headerItem.type === 'date'">
<span>{{ scope.row[headerItem.prop] }}</span>
</template>
<template v-else-if="headerItem.type === 'number'">
<span>{{ scope.row[headerItem.prop] }}</span>
</template>
<template v-else>{{ scope.row[headerItem.prop] }}</template>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="145">
<template #default="scope">
<el-button type="primary" circle @click="optClick(scope.row, 'edit')">
<el-icon>
<Edit />
</el-icon>
</el-button>
<el-button type="info" circle @click="optClick(scope.row, 'info')">
<el-icon>
<InfoFilled />
</el-icon>
</el-button>
<el-button type="danger" circle @click="optClick(scope.row, 'del')">
<el-icon>
<Delete />
</el-icon>
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination style="margin:8px 0 0 0" v-model:current-page="currentPage" v-model:page-size="pageSize"
:total="total" @size-change="handleSizeChange" layout="total, sizes, prev, pager, next, jumper"
:page-sizes="pageSizes" @current-change="handleCurrentChange" @prev-click="handleCurrentChange"
@next-click="handleCurrentChange"></el-pagination>
</div>
</template>
<script>
import _ from 'lodash'
import dayjs from 'dayjs'
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'tablecomponent',
components: {},
props: {
tableHeader: {
type: Array,
default: () => {
return []
}
},
tableData: {
type: Array,
default: () => {
return []
}
},
pageSizes: {
type: Array,
default: () => {
return [16, 50, 100, 200]
}
},
total: {
type: Number,
default: () => {
return 0
}
},
},
data() {
return {
_: _,
dayjs: dayjs,
currentPage: 1,
pageSize: 16,
}
},
methods: {
selectChange(selection) {
this.$emit("selectChange", selection)
},
handleSizeChange(pageSize) {
this.$emit("handleSizeChange", pageSize)
},
handleCurrentChange(currentPage) {
this.$emit("handleCurrentChange", currentPage)
},
optClick(row, type) {
this.$emit(type, row)
},
// key
getRowKeys(row) {
return row._id; //
},
},
async mounted() { },
watch: {},
computed: {}
}
</script>
<style scoped>
.tableClass {
text-align: center;
text-align-last: center;
}
</style>

28
front/src/renderer/src/main.js

@ -0,0 +1,28 @@
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import App from './App.vue'
import './assets/css/base.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import axios from 'axios'
import * as XLSX from 'xlsx';
const app = createApp(App)
app.config.globalProperties.$axios = axios
app.config.globalProperties.$XLSX = XLSX
// window.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = true
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(ElementPlus, {
locale: zhCn,
})
app.mount('#app')
document.addEventListener('keydown', (event) => {
const { ctrlKey, shiftKey, key } = event
if ((ctrlKey && shiftKey && key === 'I') || key === 'F12') {
return event.preventDefault()
}
})

358
front/src/renderer/src/views/chanpin.vue

@ -0,0 +1,358 @@
<template>
<div class="rightClass">
<div style="margin:0 0 8px 0">
<el-button type="primary" @click="addData">
<el-icon>
<Plus />
</el-icon>
<span>新增</span>
</el-button>
<el-button type="danger" @click="deleteData(selectionData)" :disabled="selectionData.length == 0">
<el-icon>
<Delete />
</el-icon>
<span>删除</span>
</el-button>
<div class="inputClass uploadClass">
<el-upload :show-file-list="false" v-model="fileOriData" :before-upload="beforeAvatarUpload"
:http-request="successSubmit" accept=".xls,.xlsx,.csv">
<el-button type="success">
<el-icon>
<Upload />
</el-icon>
<span>上传</span>
</el-button>
</el-upload>
</div>
<el-button type="primary" @click="searchData">
<el-icon>
<Refresh />
</el-icon>
<span>刷新</span>
</el-button>
<div class="inputClass">
<el-input v-model="searchParams.daima" style="max-width: 600px" placeholder="请输入代码" clearable
@clear="searchData" @keyup.enter="searchData">
<template #append>
<el-button @click="searchData">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
</div>
</div>
<div>
<tablecomponent :tableHeader="tableHeader" :tableData="tableData" :pageSizes="pageSizes" :total="total"
@selectChange="selectChange" @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange"
@edit="edit" @info="info" @del="del">
</tablecomponent>
</div>
<el-dialog v-model="dialogFrom.visible" :title="dialogFrom.title" width="80%">
<formcomponent :formHeader="dialogFrom.formHeader" :formData="dialogFrom.formData"
:disabled="dialogFrom.disabled">
</formcomponent>
<template #footer>
<div>
<el-button @click="cancelDialog">取消</el-button>
<el-button type="primary" @click="submitDialog"> 确认 </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import _ from 'lodash'
import tableHeaderLocal from '../assets/json/chanpin.json'
import dayjs from 'dayjs'
import tablecomponent from "../components/tablecomponent.vue"
import formcomponent from "../components/formcomponent.vue"
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'chanpin',
components: { tablecomponent, formcomponent },
data() {
return {
_: _,
dayjs: dayjs,
tableHeader: [],
formHeader: [],
tableData: [],
currentPage: 1,
pageSize: 16,
pageSizes: [16, 50, 100, 200],
total: 0,
searchParams: {
daima: ""
},
selectionData: [],
dialogFrom: {
visible: false,
title: "新增用户",
type: "add",
formHeader: [],
formData: {}
},
fileOriData: []
}
},
methods: {
/**
* 上传表格检查
*/
beforeAvatarUpload(rawFile) {
let imgList = ['text/csv', 'application/vnd.ms-excel', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]
if (imgList.indexOf(rawFile.type) === -1) {
this.$msgbox.alert('请上传excel,csv格式的表格文件!')
return false
} else if (rawFile.size / 1024 / 1024 > 50) {
this.$msgbox.alert('表格文件的大小为小于50MB,数据过多时会处理过慢')
return true
}
return true
},
//
async successSubmit(opts) {
let that = this
let file = opts.file
this.fileDealData = []
let fileReader = new FileReader()
fileReader.onload = async function () {
let data = this.result
let workbook = that.$XLSX.read(data, { type: 'binary' })
let sheetName = workbook.SheetNames[0]
let sheetData = that.$XLSX.utils.sheet_to_json(workbook.Sheets[sheetName])
let list = []
for (let i = 0; i < sheetData.length; i++) {
let element = sheetData[i];
let item = {}
for (let j = 0; j < that.tableHeader.length; j++) {
let headerItem = that.tableHeader[j];
if (element[headerItem.label]) {
if (headerItem.type === "text") {
item[headerItem.prop] = element[headerItem.label]
} else if (headerItem.type === "number") {
item[headerItem.prop] = Number(element[headerItem.label])
} else if (headerItem.type === "date") {
item[headerItem.prop] = dayjs(element[headerItem.label]).format("YYYY-MM-DD HH:mm:ss")
}
}
}
list.push(item)
}
let params = {
subType: "multi",
url: "/api/chanpinInfo",
list
}
ElMessage({
message: "数据处理中",
type: 'success'
})
await that.updateSeach(params)
setTimeout(() => {
that.updateSeach({ subType: "get" })
}, 3000);
}
fileReader.onerror = function (error) {
console.error('Error reading file:', error)
}
fileReader.readAsArrayBuffer(file)
},
//
initInfo() {
let that = this
window.electron.ipcRenderer.on('chanpinInfo', (eve, str) => {
that.tableData = []
if (str.hasError) {
ElMessage({
message: str.msg,
type: 'error'
})
} else {
if (str.msg !== "查询成功") {
ElMessage({
message: str.msg,
type: 'success'
})
}
if (_.isArray(str.list)) {
that.tableData = str.list
} else if (_.isObject(str.list)) {
that.tableData = [str.list]
}
that.total = str.count
}
})
},
//
async updateSeach(params = {}) {
let localParams = {
subType: "get",
url: "/api/chanpinInfo",
pageSize: this.pageSize,
currentPage: this.currentPage,
...params,
}
window.electron.ipcRenderer.send('sendMessage', localParams)
},
//
async searchData() {
let params = {}
if (this.searchParams.daima) {
params["daima"] = this.searchParams.daima
}
await this.updateSeach(params)
},
//
selectChange(selection) {
this.selectionData = _.cloneDeep(selection)
},
//
async handleCurrentChange(currentPage) {
this.currentPage = currentPage
await this.searchData()
},
//
async handleSizeChange(pageSize) {
this.pageSize = pageSize
await this.searchData()
},
//
cancelDialog() {
this.dialogFrom = {
visible: false,
title: "新增用户",
type: "add",
formHeader: [],
formData: {}
}
},
//
async submitDialog() {
let postMethod = ["add", "multi", "edit", "get", "del"]
if (postMethod.indexOf(this.dialogFrom.type) !== -1) {
let params = {
subType: this.dialogFrom.type,
url: "/api/chanpinInfo",
list: [{ ...this.dialogFrom.formData }]
}
await this.updateSeach(params)
await setTimeout(async () => {
await this.searchData()
}, 500);
}
this.cancelDialog()
},
//
addData() {
let formData = {}
for (let i = 0; i < this.formHeader.length; i++) {
let element = this.formHeader[i];
if (element.type === "text") {
formData[element.prop] = ""
} else if (element.type === "date") {
formData[element.prop] = dayjs().format("YYYY-MM-DD")
} else if (element.type === "number") {
formData[element.prop] = 0
}
}
this.dialogFrom = {
visible: true,
title: "新增用户",
type: "add",
disabled: false,
formHeader: this.formHeader,
formData
}
},
//
edit(row) {
this.dialogFrom = {
visible: true,
title: "编辑用户",
type: "edit",
disabled: false,
formHeader: this.formHeader,
formData: { ...row }
}
},
//
info(row) {
this.dialogFrom = {
visible: true,
title: "查看用户",
type: "info",
disabled: true,
formHeader: this.formHeader,
formData: { ...row }
}
},
//
del(row) {
this.deleteData([row])
},
//
deleteData(delList) {
let tooltipList = []
let idList = []
for (let i = 0; i < delList.length; i++) {
let element = delList[i];
tooltipList.push(element.username)
idList.push(element._id)
}
ElMessageBox.confirm(
`是否删除(${_.join(tooltipList, ",")})?`,
'danger',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'danger',
}
)
.then(async () => {
let params = {
subType: "del",
url: "/api/chanpinInfo",
ids: idList,
}
await this.updateSeach(params)
await this.searchData()
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除',
})
})
}
},
async mounted() {
this.tableHeader = _.filter(tableHeaderLocal, o => o.tableShow)
this.formHeader = _.filter(tableHeaderLocal, o => o.formShow)
this.initInfo()
await this.updateSeach()
},
watch: {},
computed: {}
}
</script>
<style scoped>
.rightClass {
padding: 0 8px 0 0;
}
.uploadClass {
top: 3px;
}
.inputClass {
display: inline-block;
margin: 0 8px;
position: relative;
}
</style>

492
front/src/renderer/src/views/dingdan.vue

@ -0,0 +1,492 @@
<template>
<div class="rightClass">
<div style="margin:0 0 8px 0">
<!-- <el-button type="primary" @click="addData">
<el-icon>
<Plus />
</el-icon>
<span>新增</span>
</el-button> -->
<el-button type="danger" @click="deleteData(selectionData)" :disabled="selectionData.length == 0">
<el-icon>
<Delete />
</el-icon>
<span>删除</span>
</el-button>
<div class="inputClass uploadClass">
<el-upload :show-file-list="false" v-model="fileOriData" :before-upload="beforeAvatarUpload"
:http-request="successSubmit" accept=".xls,.xlsx,.csv">
<el-button type="success">
<el-icon>
<Upload />
</el-icon>
<span>上传</span>
</el-button>
</el-upload>
</div>
<el-button type="primary" @click="searchData">
<el-icon>
<Refresh />
</el-icon>
<span>刷新</span>
</el-button>
<el-button type="primary" @click="exportxiaoshoudata">
<el-icon>
<Download />
</el-icon>
<span>导出销售订单</span>
</el-button>
<el-button type="primary" @click="exportS6data">
<el-icon>
<Download />
</el-icon>
<span>导出S6</span>
</el-button>
<div class="inputClass">
<el-input v-model="searchParams.kehubianhao" style="max-width: 400px" placeholder="请输入客户编号" clearable
@clear="searchData" @keyup.enter="searchData">
<template #append>
<el-button @click="searchData">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
</div>
</div>
<div>
<dingdantablecomponent :tableHeader="tableHeader" :tableData="tableData" :pageSizes="pageSizes" :total="total"
@selectChange="selectChange" @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange"
@edit="edit" @info="info" @del="del">
</dingdantablecomponent>
</div>
<el-dialog v-model="dialogFrom.visible" :title="dialogFrom.title" width="80%">
<dingdanformcomponent :formHeader="dialogFrom.formHeader" :formData="dialogFrom.formData"
:disabled="dialogFrom.disabled">
</dingdanformcomponent>
<template #footer>
<div>
<el-button @click="cancelDialog">取消</el-button>
<el-button type="primary" @click="submitDialog"> 确认 </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import _, { range } from 'lodash'
import tableHeaderLocal from '../assets/json/dingdan.json'
import dayjs from 'dayjs'
import dingdantablecomponent from "../components/dingdantablecomponent.vue"
import dingdanformcomponent from "../components/dingdanformcomponent.vue"
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'dingdan',
components: { dingdantablecomponent, dingdanformcomponent },
data() {
return {
_: _,
dayjs: dayjs,
tableHeader: [],
formHeader: [],
tableData: [],
currentPage: 1,
pageSize: 16,
pageSizes: [16, 50, 100, 200],
total: 0,
searchParams: {
kehubianhao: ""
},
selectionData: [],
dialogFrom: {
visible: false,
title: "新增用户",
type: "add",
formHeader: [],
formData: {}
},
fileOriData: [],
exportxiaoshou: [],
exportS6: [],
}
},
methods: {
/**
* 上传表格检查
*/
beforeAvatarUpload(rawFile) {
let imgList = ['text/csv', 'application/vnd.ms-excel', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]
if (imgList.indexOf(rawFile.type) === -1) {
this.$msgbox.alert('请上传excel,csv格式的表格文件!')
return false
} else if (rawFile.size / 1024 / 1024 > 50) {
this.$msgbox.alert('表格文件的大小为小于50MB,数据过多时会处理过慢')
return true
}
return true
},
//
async successSubmit(opts) {
let that = this
let file = opts.file
this.fileDealData = []
let fileReader = new FileReader()
fileReader.onload = async function () {
let data = this.result
let workbook = that.$XLSX.read(data, { type: 'binary' })
let sheetName = workbook.SheetNames[0]
let sheetData = that.$XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], { range: 1 })
let list = []
for (let i = 0; i < sheetData.length; i++) {
let element = sheetData[i];
let item = {}
for (let j = 0; j < that.tableHeader.length; j++) {
let headerItem = that.tableHeader[j];
if (element[headerItem.label]) {
if (headerItem.type === "text") {
item[headerItem.prop] = element[headerItem.label]
} else if (headerItem.type === "number") {
item[headerItem.prop] = Number(element[headerItem.label])
} else if (headerItem.type === "date") {
item[headerItem.prop] = dayjs(element[headerItem.label]).format("YYYY-MM-DD HH:mm:ss")
} else if (headerItem.type === "select") {
item[headerItem.prop] = element[headerItem.label]
}
}
}
list.push(item)
}
ElMessageBox.prompt('请输入客户编码', '导入订单信息', {
confirmButtonText: '确认',
cancelButtonText: '取消',
})
.then(async ({ value }) => {
let ele = _.find(list, o => o.kehumingcheng)
for (let i = 0; i < list.length; i++) {
let element = list[i];
element['kehumingcheng'] = ele.kehumingcheng
element['kehubianhao'] = value
}
let params = {
subType: "multi",
url: "/api/dingdanInfo",
list
}
ElMessage({
message: "数据处理中",
type: 'success'
})
await that.updateSeach(params)
setTimeout(() => {
that.updateSeach({ subType: "get" })
}, 1500);
})
.catch(() => {
ElMessage({
type: 'danger',
message: '导入失败',
})
})
}
fileReader.onerror = function (error) {
console.error('Error reading file:', error)
}
fileReader.readAsArrayBuffer(file)
},
//
initInfo() {
let that = this
window.electron.ipcRenderer.on('dingdanInfo', (eve, str) => {
that.tableData = []
if (str.hasError) {
ElMessage({
message: str.msg,
type: 'error'
})
} else {
if (str.msg !== "查询成功") {
ElMessage({
message: str.msg,
type: 'success'
})
}
if (_.isArray(str.list)) {
that.tableData = str.list
} else if (_.isObject(str.list)) {
that.tableData = [str.list]
}
that.total = str.count
}
})
},
//
exportData() {
let that = this
window.electron.ipcRenderer.on('Dingdan', (eve, str) => {
if (str.hasError) {
ElMessage({
message: str.msg,
type: 'error'
})
} else {
ElMessage({
message: str.msg,
type: 'success'
})
this[`deal${str.subType}`](str.list)
}
})
},
//
async updateSeach(params = {}) {
let localParams = {
subType: "get",
url: "/api/dingdanInfo",
// url:"/api/chanpinInfo",
pageSize: this.pageSize,
currentPage: this.currentPage,
...params,
}
window.electron.ipcRenderer.send('sendMessage', _.cloneDeep(localParams))
},
//
async searchData() {
let params = {}
if (this.searchParams.kehubianhao) {
params["kehubianhao"] = this.searchParams.kehubianhao
}
this.updateSeach(params)
},
//
selectChange(selection) {
this.selectionData = _.cloneDeep(selection)
},
//
async handleCurrentChange(currentPage) {
this.currentPage = currentPage
await this.searchData()
},
//
async handleSizeChange(pageSize) {
this.pageSize = pageSize
await this.searchData()
},
//
cancelDialog() {
this.dialogFrom = {
visible: false,
title: "新增用户",
type: "add",
formHeader: [],
formData: {}
}
},
//
async submitDialog() {
let postMethod = ["add", "multi", "edit", "get", "del"]
if (postMethod.indexOf(this.dialogFrom.type) !== -1) {
let params = {
subType: this.dialogFrom.type,
url: "/api/dingdanInfo",
list: [{ ...this.dialogFrom.formData }]
}
await this.updateSeach(params)
await setTimeout(async () => {
await this.searchData()
}, 500);
}
this.cancelDialog()
},
//
addData() {
let formData = {}
for (let i = 0; i < this.formHeader.length; i++) {
let element = this.formHeader[i];
if (element.type === "text") {
formData[element.prop] = ""
} else if (element.type === "date") {
formData[element.prop] = dayjs().format("YYYY-MM-DD")
} else if (element.type === "number") {
formData[element.prop] = 0
}
}
this.dialogFrom = {
visible: true,
title: "新增用户",
type: "add",
disabled: false,
formHeader: this.formHeader,
formData
}
},
//
edit(row) {
this.dialogFrom = {
visible: true,
title: "编辑用户",
type: "edit",
disabled: false,
formHeader: this.formHeader,
formData: { ...row }
}
},
//
info(row) {
this.dialogFrom = {
visible: true,
title: "查看用户",
type: "info",
disabled: true,
formHeader: this.formHeader,
formData: { ...row }
}
},
//
del(row) {
this.deleteData([row])
},
//
deleteData(delList) {
let tooltipList = []
let idList = []
for (let i = 0; i < delList.length; i++) {
let element = delList[i];
tooltipList.push(element.username)
idList.push(element._id)
}
ElMessageBox.confirm(
`是否删除(${_.join(tooltipList, ",")})?`,
'danger',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'danger',
}
)
.then(async () => {
let params = {
subType: "del",
url: "/api/dingdanInfo",
ids: idList,
}
await this.updateSeach(params)
await this.searchData()
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除',
})
})
},
//
exportxiaoshoudata() {
let params = {
subType: "exportxiaoshou",
url: "/api/exportDingdanInfo",
model: "Dingdan",
// S6
}
if (this.searchParams.kehubianhao) {
params["kehubianhao"] = this.searchParams.kehubianhao
}
window.electron.ipcRenderer.send('exportData', params)
},
//S6
exportS6data() {
let params = {
subType: "exportS6",
url: "/api/exportDingdanInfo",
model: "Dingdan",
// S6
}
if (this.searchParams.kehubianhao) {
params["kehubianhao"] = this.searchParams.kehubianhao
}
window.electron.ipcRenderer.send('exportData', params)
},
//
dealexportxiaoshou(list) {
let lilstLocal = []
let allMoney = 0
for (let i = 0; i < list.length; i++) {
let item = list[i];
let listItem = {}
allMoney += item.xiaoshoujine
for (let j = 0; j < this.exportxiaoshou.length; j++) {
let headerItem = this.exportxiaoshou[j];
listItem[headerItem.label] = item[headerItem.prop]
}
lilstLocal.push(listItem)
}
lilstLocal.push({ "销售金额": allMoney })
let jsonWorkSheet = this.$XLSX.utils.json_to_sheet(lilstLocal);
let workBook = {
SheetNames: ["sheet1"],
Sheets: {
["sheet1"]: jsonWorkSheet,
}
};
return this.$XLSX.writeFile(workBook, `销售订单${dayjs().format("YYYY-MM-DD_HH-mm-ss")}.xlsx`);
},
//S6
dealexportS6(list) {
let lilstLocal = []
let allMoney = 0
for (let i = 0; i < list.length; i++) {
let item = list[i];
let listItem = {}
allMoney += item.danjudanweishuliang
for (let j = 0; j < this.exportS6.length; j++) {
let headerItem = this.exportS6[j];
listItem[headerItem.label] = item[headerItem.prop]
}
lilstLocal.push(listItem)
}
lilstLocal.push({ "单据单位数量": allMoney })
let jsonWorkSheet = this.$XLSX.utils.json_to_sheet(lilstLocal);
let workBook = {
SheetNames: ["sheet1"],
Sheets: {
["sheet1"]: jsonWorkSheet,
}
};
return this.$XLSX.writeFile(workBook, `S6订单${dayjs().format("YYYY-MM-DD_HH-mm-ss")}.xlsx`);
},
},
async mounted() {
this.tableHeader = _.filter(tableHeaderLocal, o => o.tableShow)
this.formHeader = _.filter(tableHeaderLocal, o => o.formShow)
this.exportxiaoshou = _.filter(tableHeaderLocal, o => o.exportxiaoshou)
this.exportS6 = _.filter(tableHeaderLocal, o => o.exportS6)
this.initInfo()
this.exportData()
await this.updateSeach()
},
watch: {},
computed: {}
}
</script>
<style scoped>
.rightClass {
padding: 0 8px 0 0;
}
.uploadClass {
top: 3px;
}
.inputClass {
display: inline-block;
margin: 0 8px;
position: relative;
}
</style>

359
front/src/renderer/src/views/user.vue

@ -0,0 +1,359 @@
<template>
<div class="rightClass">
<div style="margin:0 0 8px 0">
<el-button type="primary" @click="addData">
<el-icon>
<Plus />
</el-icon>
<span>新增</span>
</el-button>
<el-button type="danger" @click="deleteData(selectionData)" :disabled="selectionData.length == 0">
<el-icon>
<Delete />
</el-icon>
<span>删除</span>
</el-button>
<div class="inputClass uploadClass">
<el-upload :show-file-list="false" v-model="fileOriData" :before-upload="beforeAvatarUpload"
:http-request="successSubmit" accept=".xls,.xlsx,.csv">
<el-button type="success">
<el-icon>
<Upload />
</el-icon>
<span>上传</span>
</el-button>
</el-upload>
</div>
<el-button type="primary" @click="searchData">
<el-icon>
<Refresh />
</el-icon>
<span>刷新</span>
</el-button>
<div class="inputClass">
<el-input v-model="searchParams.usercode" style="max-width: 600px" placeholder="请输入客户编号" clearable
@clear="searchData" @keyup.enter="searchData">
<template #append>
<el-button @click="searchData">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
</div>
</div>
<div>
<tablecomponent :tableHeader="tableHeader" :tableData="tableData" :pageSizes="pageSizes" :total="total"
@selectChange="selectChange" @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange"
@edit="edit" @info="info" @del="del">
</tablecomponent>
</div>
<el-dialog v-model="dialogFrom.visible" :title="dialogFrom.title" width="80%">
<formcomponent :formHeader="dialogFrom.formHeader" :formData="dialogFrom.formData"
:disabled="dialogFrom.disabled">
</formcomponent>
<template #footer>
<div>
<el-button @click="cancelDialog">取消</el-button>
<el-button type="primary" @click="submitDialog"> 确认 </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import _ from 'lodash'
import tableHeaderLocal from '../assets/json/user.json'
import dayjs from 'dayjs'
import tablecomponent from "../components/tablecomponent.vue"
import formcomponent from "../components/formcomponent.vue"
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'user',
components: { tablecomponent, formcomponent },
data() {
return {
_: _,
dayjs: dayjs,
tableHeader: [],
formHeader: [],
tableData: [],
currentPage: 1,
pageSize: 16,
pageSizes: [16, 50, 100, 200],
total: 0,
searchParams: {
usercode: ""
},
selectionData: [],
dialogFrom: {
visible: false,
title: "新增用户",
type: "add",
formHeader: [],
formData: {}
},
fileOriData: []
}
},
methods: {
/**
* 上传表格检查
*/
beforeAvatarUpload(rawFile) {
let imgList = ['text/csv', 'application/vnd.ms-excel', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]
if (imgList.indexOf(rawFile.type) === -1) {
this.$msgbox.alert('请上传excel,csv格式的表格文件!')
return false
} else if (rawFile.size / 1024 / 1024 > 50) {
this.$msgbox.alert('表格文件的大小为小于50MB,数据过多时会处理过慢')
return true
}
return true
},
//
async successSubmit(opts) {
let that = this
let file = opts.file
this.fileDealData = []
let fileReader = new FileReader()
fileReader.onload = async function () {
let data = this.result
let workbook = that.$XLSX.read(data, { type: 'binary' })
let sheetName = workbook.SheetNames[0]
let sheetData = that.$XLSX.utils.sheet_to_json(workbook.Sheets[sheetName])
let list = []
for (let i = 0; i < sheetData.length; i++) {
let element = sheetData[i];
let item = {}
for (let j = 0; j < that.tableHeader.length; j++) {
let headerItem = that.tableHeader[j];
if (element[headerItem.label]) {
if (headerItem.type === "text") {
item[headerItem.prop] = element[headerItem.label]
} else if (headerItem.type === "number") {
item[headerItem.prop] = Number(element[headerItem.label])
} else if (headerItem.type === "date") {
item[headerItem.prop] = dayjs(element[headerItem.label]).format("YYYY-MM-DD HH:mm:ss")
}
}
}
list.push(item)
}
let params = {
subType: "multi",
url: "/api/userInfo",
list
}
ElMessage({
message: "数据处理中",
type: 'success'
})
await that.updateSeach(params)
setTimeout(() => {
that.updateSeach()
}, 1500);
}
fileReader.onerror = function (error) {
console.error('Error reading file:', error)
}
fileReader.readAsArrayBuffer(file)
},
//
initInfo() {
let that = this
window.electron.ipcRenderer.on('userInfo', (eve, str) => {
that.tableData = []
if (str.hasError) {
ElMessage({
message: str.msg,
type: 'error'
})
} else {
if (str.msg !== "查询成功") {
ElMessage({
message: str.msg,
type: 'success',
grouping: true
})
}
if (_.isArray(str.list)) {
that.tableData = str.list
} else if (_.isObject(str.list)) {
that.tableData = [str.list]
}
that.total = str.count
}
})
},
//
async updateSeach(params = {}) {
let localParams = {
subType: "get",
url: "/api/userInfo",
pageSize: this.pageSize,
currentPage: this.currentPage,
...params,
}
window.electron.ipcRenderer.send('sendMessage', localParams)
},
//
async searchData() {
let params = {}
if (this.searchParams.usercode) {
params["usercode"] = this.searchParams.usercode
}
this.updateSeach(params)
},
//
selectChange(selection) {
this.selectionData = _.cloneDeep(selection)
},
//
async handleCurrentChange(currentPage) {
this.currentPage = currentPage
await this.searchData()
},
//
async handleSizeChange(pageSize) {
this.pageSize = pageSize
await this.searchData()
},
//
cancelDialog() {
this.dialogFrom = {
visible: false,
title: "新增用户",
type: "add",
formHeader: [],
formData: {}
}
},
//
async submitDialog() {
let postMethod = ["add", "multi", "edit", "get", "del"]
if (postMethod.indexOf(this.dialogFrom.type) !== -1) {
let params = {
subType: this.dialogFrom.type,
url: "/api/userInfo",
list: [{ ...this.dialogFrom.formData }]
}
await this.updateSeach(params)
await setTimeout(async () => {
await this.searchData()
}, 500);
}
this.cancelDialog()
},
//
addData() {
let formData = {}
for (let i = 0; i < this.formHeader.length; i++) {
let element = this.formHeader[i];
if (element.type === "text") {
formData[element.prop] = ""
} else if (element.type === "date") {
formData[element.prop] = dayjs().format("YYYY-MM-DD")
} else if (element.type === "number") {
formData[element.prop] = 0
}
}
this.dialogFrom = {
visible: true,
title: "新增用户",
type: "add",
disabled: false,
formHeader: this.formHeader,
formData
}
},
//
edit(row) {
this.dialogFrom = {
visible: true,
title: "编辑用户",
type: "edit",
disabled: false,
formHeader: this.formHeader,
formData: { ...row }
}
},
//
info(row) {
this.dialogFrom = {
visible: true,
title: "查看用户",
type: "info",
disabled: true,
formHeader: this.formHeader,
formData: { ...row }
}
},
//
del(row) {
this.deleteData([row])
},
//
deleteData(delList) {
let tooltipList = []
let idList = []
for (let i = 0; i < delList.length; i++) {
let element = delList[i];
tooltipList.push(element.username)
idList.push(element._id)
}
ElMessageBox.confirm(
`是否删除(${_.join(tooltipList, ",")})?`,
'danger',
{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'danger',
}
)
.then(async () => {
let params = {
subType: "del",
url: "/api/userInfo",
ids: idList,
}
await this.updateSeach(params)
await this.searchData()
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除',
})
})
}
},
async mounted() {
this.tableHeader = _.filter(tableHeaderLocal, o => o.tableShow)
this.formHeader = _.filter(tableHeaderLocal, o => o.formShow)
this.initInfo()
await this.updateSeach()
},
watch: {},
computed: {}
}
</script>
<style scoped>
.rightClass {
padding: 0 8px 0 0;
}
.uploadClass {
top: 3px;
}
.inputClass {
display: inline-block;
margin: 0 8px;
position: relative;
}
</style>

BIN
模版/S6直营销售单导入模板.xls

Binary file not shown.

BIN
模版/产品信息(模板).xls

Binary file not shown.

BIN
模版/客户编码文档(1).xls

Binary file not shown.

BIN
模版/销售订单修改导出(审核版).xlsx

Binary file not shown.

BIN
模版/销售订单导入准备表(1).xlsx

Binary file not shown.

BIN
模版/销售订单导出第一步(未审核版).xlsx

Binary file not shown.

BIN
模版/销售订单未导入产品.xlsx

Binary file not shown.
Loading…
Cancel
Save