asd123a20 3 years ago
parent
commit
dcc5d2f8ea

+ 30 - 0
.autod.conf.js

@@ -0,0 +1,30 @@
+'use strict';
+
+module.exports = {
+  write: true,
+  prefix: '^',
+  plugin: 'autod-egg',
+  test: [
+    'test',
+    'benchmark',
+  ],
+  dep: [
+    'egg',
+    'egg-scripts',
+  ],
+  devdep: [
+    'egg-ci',
+    'egg-bin',
+    'egg-mock',
+    'autod',
+    'autod-egg',
+    'eslint',
+    'eslint-config-egg',
+    'webstorm-disable-index',
+  ],
+  exclude: [
+    './test/fixtures',
+    './dist',
+  ],
+};
+

+ 1 - 0
.eslintignore

@@ -0,0 +1 @@
+coverage

+ 3 - 0
.eslintrc

@@ -0,0 +1,3 @@
+{
+  "extends": "eslint-config-egg-naf"
+}

+ 12 - 0
.gitignore

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

+ 12 - 0
.travis.yml

@@ -0,0 +1,12 @@
+
+language: node_js
+node_js:
+  - '8'
+before_install:
+  - npm i npminstall -g
+install:
+  - npminstall
+script:
+  - npm run ci
+after_script:
+  - npminstall codecov && codecov

+ 39 - 0
README.zh-CN.md

@@ -0,0 +1,39 @@
+# naf-code
+
+
+
+## 快速入门
+
+<!-- 在此次添加使用文档 -->
+
+如需进一步了解,参见 [egg 文档][egg]。
+
+### 本地开发
+
+```bash
+$ npm i
+$ npm run dev
+$ open http://localhost:7001/
+```
+
+### 部署
+
+```bash
+$ npm start
+$ npm stop
+```
+
+### 单元测试
+
+- [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。
+- 断言库非常推荐使用 [power-assert]。
+- 具体参见 [egg 文档 - 单元测试](https://eggjs.org/zh-cn/core/unittest)。
+
+### 内置指令
+
+- 使用 `npm run lint` 来做代码风格检查。
+- 使用 `npm test` 来执行单元测试。
+- 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod) 。
+
+
+[egg]: https://eggjs.org

+ 14 - 0
app/controller/api.js

@@ -0,0 +1,14 @@
+'use strict';
+
+const Controller = require('egg').Controller;
+const meta = require('./api.json');
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+class ItemsController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.api;
+  }
+}
+
+module.exports = CrudController(ItemsController, meta);

+ 16 - 0
app/controller/api.json

@@ -0,0 +1,16 @@
+{
+  "list": {
+    "params": ["category", "group"],
+    "service": "list",
+    "options": {
+      "sort": {"order": -1, "code": 1}
+    }
+  },
+  "fetch": {
+    "params": ["category", "group"],
+    "query": ["code"]
+  },
+  "xzqh": {
+    "query": ["parent", "level"]
+  }
+}

+ 14 - 0
app/controller/category.js

@@ -0,0 +1,14 @@
+'use strict';
+
+const Controller = require('egg').Controller;
+const meta = require('./category.json');
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+class CategoryController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.category;
+  }
+}
+
+module.exports = CrudController(CategoryController, meta);

+ 24 - 0
app/controller/category.json

@@ -0,0 +1,24 @@
+{
+  "create": {
+    "requestBody": ["code","name","key","order"]
+  },
+  "delete": {
+    "query": ["code"]
+  },
+  "update": {
+    "parameters": {
+      "query": ["code"]
+    },
+    "requestBody": ["name","key","order"]
+  },
+  "list": {
+    "parameters": {},
+    "service": "query",
+    "options": {
+      "sort": {"order": -1, "code": 1}
+    }
+  },
+  "fetch": {
+    "query": ["code"]
+  }
+}

+ 15 - 0
app/controller/home.js

@@ -0,0 +1,15 @@
+'use strict';
+
+const Controller = require('egg').Controller;
+
+class HomeController extends Controller {
+  async index() {
+    this.ctx.body = 'naf code service';
+  }
+
+  async demo() {
+    this.ctx.success({ data: 'ok' });
+  }
+}
+
+module.exports = HomeController;

+ 14 - 0
app/controller/items.js

@@ -0,0 +1,14 @@
+'use strict';
+
+const Controller = require('egg').Controller;
+const meta = require('./items.json');
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+class ItemsController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.items;
+  }
+}
+
+module.exports = CrudController(ItemsController, meta);

+ 40 - 0
app/controller/items.json

@@ -0,0 +1,40 @@
+{
+  "create": {
+    "params": ["category"],
+    "requestBody": ["code", "name", "group", "order", "status"]
+  },
+  "delete": {
+    "params": ["category"],
+    "query": ["code"]
+  },
+  "update": {
+    "parameters": {
+      "params": ["category"],
+      "query": ["code"]
+    },
+    "requestBody": ["name", "group", "order", "status"]
+  },
+  "list": {
+    "parameters": {
+      "params": ["category"],
+      "query": ["group", "status"]
+    },
+    "service": "query",
+    "options": {
+      "sort": {"order": -1, "code": 1},
+      "query": ["skip", "limit"],
+      "count": true
+    }
+  },
+  "fetch": {
+    "params": ["category"],
+    "query": ["code"]
+  },
+  "clear": {
+    "params": ["category"],
+    "service": { 
+      "name": "category",
+      "func": "clear"
+    }
+  }
+}

+ 17 - 0
app/model/category.js

@@ -0,0 +1,17 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+
+const SchemaDefine = {
+  code: { type: String, required: true, maxLength: 64 },
+  name: { type: String, required: true, maxLength: 128 },
+  key: { type: String, required: true, maxLength: 64 },
+  order: Number,
+};
+const schema = new Schema(SchemaDefine);
+schema.index({ code: 1 }, { unique: true });
+schema.index({ key: 1 });
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('CodeCategory', schema, 'naf_code_category');
+};

+ 23 - 0
app/model/items.js

@@ -0,0 +1,23 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+
+const SchemaDefine = {
+  code: { type: String, required: true, maxLength: 64 },
+  name: { type: String, required: true, maxLength: 128 },
+  category: { type: String, required: true, maxLength: 64 }, // 字典类别
+  group: { type: String, required: false, maxLength: 64, default: '0' }, // 数据子类/分组
+  status: { type: String, maxLength: 64, default: '0' },
+  order: { type: Number, default: 0 },
+};
+const schema = new Schema(SchemaDefine);
+schema.index({ code: 1 });
+schema.index({ category: 1 });
+schema.index({ category: 1, group: 1 });
+schema.index({ category: 1, code: 1 }, { unique: true });
+schema.index({ category: 1, order: 1 });
+schema.index({ category: 1, group: 1, order: 1 });
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('CodeItems', schema, 'naf_code_items');
+};

+ 32 - 0
app/router.js

@@ -0,0 +1,32 @@
+'use strict';
+
+/**
+ * @param {Egg.Application} app - egg application
+ */
+module.exports = app => {
+  const { router, controller } = app;
+  router.get('/', controller.home.index);
+  router.all('/demo', controller.home.demo);
+
+  // 开放接口
+  router.get('/naf/xzqh/list', controller.api.xzqh);
+  router.get('/naf/category/:category/list', controller.api.list);
+  router.get('/naf/category/:category/:group/list', controller.api.list);
+  router.get('/naf/category/:category/fetch', controller.api.fetch);
+  router.get('/naf/category/:category/:group/fetch', controller.api.fetch);
+
+  // 字典分类
+  router.get('/naf/category/list', controller.category.list);
+  router.get('/naf/category/fetch', controller.category.fetch);
+  router.post('/naf/category/create', controller.category.create);
+  router.post('/naf/category/update', controller.category.update);
+  router.get('/naf/category/delete', controller.category.delete);
+
+  // 字典项
+  router.get('/naf/items/:category/list', controller.items.list);
+  router.get('/naf/items/:category/fetch', controller.items.fetch);
+  router.post('/naf/items/:category/create', controller.items.create);
+  router.post('/naf/items/:category/update', controller.items.update);
+  router.get('/naf/items/:category/delete', controller.items.delete);
+  router.get('/naf/items/:category/clear', controller.items.clear);
+};

+ 58 - 0
app/service/api.js

@@ -0,0 +1,58 @@
+'use strict';
+
+const assert = require('assert');
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+const { isNullOrUndefined, trimData } = require('naf-core').Util;
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+
+class ApiService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'naf_code_items');
+    this.mItems = this.ctx.model.Items;
+    this.mCategory = this.ctx.model.Category;
+    this.model = this.mItems;
+  }
+
+  async list({ category, group } = {}) {
+    assert(category, '类别不能为空');
+    // const rs = await this.model.find(trimData(data), null, trimData({ skip, limit, sort: order && { [order]: 1 } })).exec();
+    const c = await this.mCategory.findOne({ $or: [{ code: category }, { key: category }] }).exec();
+    if (isNullOrUndefined(c)) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '字典类别不存在');
+    }
+    const rs = await this.mItems.find(trimData({ category: c.code, group }), { code: 1, name: 1, _id: -1 }, { sort: { order: -1, code: 1 } }).exec();
+    return rs.map(p => ({ code: p.code, name: p.name }));
+  }
+
+  async xzqh({ parent, level } = {}) {
+    assert(isNullOrUndefined(parent) || /^\d{6}$/.test(parent), 'parent必须为有效的行政区划代码');
+    assert(level, 'level不能为空');
+    if (!_.isNumber(level)) level = Number(level);
+    assert(level >= 0 && level <= 3, 'level只能为0~3的数字');
+
+    const filter = { category: '31' };
+    if (level > 0) {
+      const suffix = '000000'.substr(0, (3 - level) * 2);
+      let prefix = '';
+      if (!isNullOrUndefined(parent) && level > 1) prefix = parent.substr(0, (level - 1) * 2);
+      filter.code = { $regex: `${prefix}\\d{2}(?<!00)${suffix}` };
+    }
+    const rs = await this.mItems.find(filter, { code: 1, name: 1, _id: -1 }, { sort: { order: -1, code: 1 } }).exec();
+    return rs.map(p => ({ code: p.code, name: p.name }));
+  }
+
+  async fetch({ category, group, code } = {}) {
+    assert(category, 'category不能为空');
+    assert(code, 'code不能为空');
+    // const rs = await this.model.find(trimData(data), null, trimData({ skip, limit, sort: order && { [order]: 1 } })).exec();
+    const c = await this.mCategory.findOne({ $or: [{ code: category }, { key: category }] }).exec();
+    if (isNullOrUndefined(c)) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '字典类别不存在');
+    }
+    const rs = await this.mItems.findOne({ category: c.code, group, code }, { code: 1, name: 1, _id: -1 }).exec();
+    return rs;
+  }
+}
+
+module.exports = ApiService;

+ 53 - 0
app/service/category.js

@@ -0,0 +1,53 @@
+'use strict';
+
+const assert = require('assert');
+const { isNullOrUndefined } = require('naf-core').Util;
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+
+class CategoryService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'naf_code_category');
+    this.mItems = this.ctx.model.Items;
+    this.mCategory = this.ctx.model.Category;
+    this.model = this.mCategory;
+  }
+
+  async delete({ code }) {
+    assert(code, 'code不能为空');
+
+    // TODO:检查数据是否存在
+    const entity = await this.mCategory.findOne({ code }).exec();
+    if (isNullOrUndefined(entity)) throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
+
+    // TODO: 检查是否包含字典项数据
+    const count = await this.mItems.count({ category: entity.code }).exec();
+    if (count > 0) {
+      throw new BusinessError(ErrorCode.SERVICE_FAULT, '存在字典项数据,不能删除');
+    }
+
+    await this.mCategory.deleteOne({ _id: entity._id }).exec();
+    return 'deleted';
+  }
+
+  async clear({ category }) {
+    assert(category, 'category不能为空');
+
+    // TODO:检查数据是否存在
+    const entity = await this.mCategory.findOne({ code: category }).exec();
+    if (isNullOrUndefined(entity)) throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
+
+    // TODO: 删除字典项数据
+    await this.mItems.deleteMany({ category: entity.code }).exec();
+    return 'cleared';
+  }
+
+  // async query({ skip, limit, order } = {}, data = {}) {
+  //   // const rs = await this._find(trimData(data), null, trimData({ skip, limit, sort: order && { [order]: 1 } }));
+  //   const rs = await this.model.find({}, null, {}).exec();
+  //   return rs;
+  // }
+
+}
+
+module.exports = CategoryService;

+ 42 - 0
app/service/items.js

@@ -0,0 +1,42 @@
+'use strict';
+
+const assert = require('assert');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+
+class ItemsService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'naf_code_items');
+    this.mCategory = this.ctx.model.Category;
+    this.mItems = this.ctx.model.Items;
+    this.model = this.mItems;
+  }
+
+  async create({ category }, data) {
+    assert(category);
+    assert(data);
+
+    // TODO:检查类别是否存在
+    const c = await this.mCategory.findOne({ code: category }).exec();
+    if (!c) {
+      this.logger.error(`code category: ${category} not exist!`);
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '类别信息不存在');
+    }
+
+    // TODO:保存数据
+    const res = await this.mItems.create({ ...data, category });
+    return res;
+  }
+
+  async delete({ category, code }) {
+    assert(category, 'category不能为空');
+    assert(code, 'code不能为空');
+
+    await this.mItems.deleteOne({ category, code }).exec();
+    return 'deleted';
+  }
+
+
+}
+
+module.exports = ItemsService;

+ 14 - 0
appveyor.yml

@@ -0,0 +1,14 @@
+environment:
+  matrix:
+    - nodejs_version: '8'
+
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - npm i npminstall && node_modules\.bin\npminstall
+
+test_script:
+  - node --version
+  - npm --version
+  - npm run test
+
+build: off

+ 36 - 0
config/config.default.js

@@ -0,0 +1,36 @@
+'use strict';
+
+module.exports = appInfo => {
+  const config = exports = {};
+
+  // use for cookie sign key, should change to your own and keep security
+  config.keys = appInfo.name + '_1516694643431_7736';
+
+  // add your config here
+  // config.middleware = [ ];
+  config.errorMongo = {
+    details: true,
+  };
+  config.errorHanler = {
+    details: true,
+  };
+
+  // mongoose config
+  config.mongoose = {
+    url: 'mongodb://localhost:27018/naf',
+    options: {
+      user: 'root',
+      pass: 'cms@cc-lotus',
+      authSource: 'admin',
+      useNewUrlParser: true,
+      useCreateIndex: true,
+    },
+  };
+
+  config.logger = {
+    // level: 'DEBUG',
+    consoleLevel: 'DEBUG',
+  };
+
+  return config;
+};

+ 24 - 0
config/config.local.js

@@ -0,0 +1,24 @@
+'use strict';
+
+module.exports = () => {
+  const config = exports = {};
+
+  config.cluster = {
+    listen: {
+      port: 8002,
+    },
+  };
+
+  // mongoose config
+  config.mongoose = {
+    url: 'mongodb://127.0.0.1:27017/naf',
+    options: {},
+    // url: 'mongodb://192.168.1.170:27018/naf',
+  };
+
+  config.logger = {
+    consoleLevel: 'DEBUG',
+  };
+
+  return config;
+};

+ 31 - 0
config/config.prod.js

@@ -0,0 +1,31 @@
+'use strict';
+
+module.exports = () => {
+  const config = exports = {};
+
+  // add your config here
+  config.cluster = {
+    listen: {
+      port: 8002,
+    },
+  };
+
+  // mongoose config
+  config.mongoose = {
+    url: 'mongodb://localhost:27018/naf',
+    options: {
+      user: 'root',
+      pass: 'Ziyouyanfa#@!',
+      authSource: 'admin',
+      useNewUrlParser: true,
+      useCreateIndex: true,
+    },
+  };
+
+  config.logger = {
+    // level: 'DEBUG',
+    // consoleLevel: 'DEBUG',
+  };
+
+  return config;
+};

+ 8 - 0
config/plugin.js

@@ -0,0 +1,8 @@
+'use strict';
+
+// had enabled by egg
+// exports.static = true;
+
+exports.multiTenancy = {
+  enable: false,
+};

+ 74 - 0
data/21.院校代码.csv

@@ -0,0 +1,74 @@
+10183,吉林大学
+10184,延边大学
+10186,长春理工大学
+10188,东北电力大学
+10190,长春工业大学
+10191,吉林建筑大学
+10192,吉林化工学院
+10193,吉林农业大学
+10199,长春中医药大学
+10200,东北师范大学
+10201,北华大学
+10202,通化师范学院
+10203,吉林师范大学
+10204,吉林工程技术师范学院
+10205,长春师范大学
+10206,白城师范学院
+10207,吉林财经大学
+10208,吉林体育学院
+10209,吉林艺术学院
+10847,辽源职业技术学院
+10964,吉林华桥外国语学院
+11044,四平职业大学
+11261,吉林工商学院
+11436,长春汽车工业高等专科学校
+11437,长春工程学院
+11439,吉林农业科技学院
+11440,长春金融高等专科学校
+11441,吉林警察学院
+11726,长春大学
+11823,长春医学高等专科学校
+12049,吉林交通职业技术学院
+12306,长春东方职业学院
+12345,研究生测试学校
+12901,吉林司法警官职业学院
+12902,吉林电子信息职业技术学院
+12903,吉林工业职业技术学院
+12904,吉林农业工程职业技术学院
+13161,长春职业技术学院
+13600,长春光华学院
+13601,长春工业大学人文信息学院
+13602,长春理工大学光电信息学院
+13603,长春财经学院
+13604,吉林建筑大学城建学院
+13605,长春建筑学院
+13606,长春科技学院
+13607,吉林动画学院
+13622,吉林师范大学博达学院
+13623,长春大学旅游学院
+13662,东北师范大学人文学院
+13706,吉林医药学院
+13743,白城医学高等专科学校
+13916,长春信息技术职业学院
+13917,松原职业技术学院
+14052,吉林铁道职业技术学院
+14107,白城职业技术学院
+14190,长白山职业技术学院
+14291,吉林科技职业技术学院
+14340,延边职业技术学院
+14426,吉林城市职业技术学院
+50252,吉林省教育学院
+51243,吉林省经济管理干部学院
+80037,中科院长春应用化学研究所
+80062,中科院东北地理与农业生态研究所
+80139,中国科学院长春光学精密机械与物理研究所
+84509,长春生物制品研究所
+89622,中共吉林省委党校
+95085,吉林卫生学校
+99001,吉林省石油学校
+99004,吉林航空工程学校
+99005,吉林省体育运动学校
+99006,吉林省城市建设学校
+99024,长春水利电力学校
+99025,吉林工业经济学校
+99037,吉林省畜牧业学校

+ 19 - 0
data/22.学历类型.csv

@@ -0,0 +1,19 @@
+01,博士生毕业
+03,博士生结业
+09,博士生肆业
+11,硕士生毕业
+13,硕士生结业
+19,硕士生肆业
+21,研班毕业
+25,双学位毕业
+31,本科生毕业
+33,本科生结业
+39,本科生肆业
+41,专科生毕业
+43,专科生结业
+49,专科生肆业
+51,中专生毕业
+53,中专生结业
+59,中专生肆业
+61,高职毕业
+63,高职结业

+ 4 - 0
data/23.培养方式.csv

@@ -0,0 +1,4 @@
+0,----
+1,非定向
+2,定向
+9,其他

File diff suppressed because it is too large
+ 3219 - 0
data/31.行政区划.csv


+ 56 - 0
data/32.民族.csv

@@ -0,0 +1,56 @@
+01,ºº×å
+02,ÃɹÅ×å
+03,»Ø×å
+04,²Ø×å
+05,άÎá¶û×å
+06,Ãç×å
+07,ÒÍ×å
+08,׳×å
+09,²¼ÒÀ×å
+10,³¯ÏÊ×å
+11,Âú×å
+12,¶±×å
+13,Ñþ×å
+14,°××å
+15,ÍÁ¼Ò×å
+16,¹þÄá×å
+17,¹þÈø¿Ë×å
+18,´ö×å
+19,Àè×å
+20,ÀüËÛ×å
+21,Øô×å
+22,î´×å
+23,¸ßɽ×å
+24,À­ìï×å
+25,Ë®×å
+26,¶«Ïç×å
+27,ÄÉÎ÷×å
+28,¾°ÆÄ×å
+29,¿Â¶û¿Ë×Î×å
+30,ÍÁ×å
+31,´ïÎÓ¶û×å
+32,ØïÀÐ×å
+33,Ǽ×å
+34,²¼ÀÊ×å
+35,ÈöÀ­×å
+36,ëÄÑ×å
+37,ØîÀÐ×å
+38,Îý²®×å
+39,°¢²ý×å
+40,ÆÕÃ××å
+41,Ëþ¼ª¿Ë×å
+42,Å­×å
+43,ÎÚ×αð¿Ë×å
+44,¶íÂÞ˹×å
+45,¶õοË×å
+46,µÂ°º×å
+47,±£°²×å
+48,Ô£¹Ì×å
+49,¾©×å
+50,ËþËþ¶û×å
+51,¶ÀÁú×å
+52,¶õÂ×´º×å
+53,ºÕÕÜ×å
+54,ÃŰÍ×å
+55,çó°Í×å
+56,»ùŵ×å

+ 4 - 0
data/33.性别.csv

@@ -0,0 +1,4 @@
+0,未知的性别
+1,男
+2,女
+9,未说明的性别

+ 13 - 0
data/34.政治面貌.csv

@@ -0,0 +1,13 @@
+01,中国共产党党员
+02,中国共产党预备党员
+03,中国共产主义青年团团员
+04,中国国民党革命委员会会员
+05,中国民主同盟盟员
+06,中国民主建国会会员
+07,中国民主促进会会员
+08,中国农工民主党党员
+09,中国致公党党员
+10,九三学社社员
+11,台湾民主自治同盟盟员
+12,无党派民主人士
+13,群众

+ 21 - 0
data/35.行业类别.csv

@@ -0,0 +1,21 @@
+01,农、林、牧、渔业
+02,采矿业
+03,制造业
+04,电力、热力、燃气及水生产和供应业
+05,建筑业
+06,批发和零售业
+07,交通运输、仓储和邮政业
+08,住宿和餐饮业
+09,信息传输、软件和信息技术服务业
+10,金融业
+11,房地产业
+12,租赁和商务服务业
+13,科学研究和技术服务业
+14,水利、环境和公共设施管理业
+15,居民服务、修理和其他服务业
+16,教育
+17,卫生和社会工作
+18,文化、体育和娱乐业
+19,公共管理、社会保障和社会组织
+20,国际组织
+99,其他

+ 14 - 0
data/36.单位性质.csv

@@ -0,0 +1,14 @@
+10,行政单位
+20,事业单位
+21,科研设计单位
+22,高等学校
+23,其它教学单位
+24,医疗单位
+29,其它事业单位
+30,企业
+31,国有企业
+32,三资企业
+33,民营企业
+39,其它企业
+40,部队
+99,其它

+ 4 - 0
data/37.单位规模.csv

@@ -0,0 +1,4 @@
+1,ノルモレ50ネヒ
+2,50-300ネヒ
+3,301-1000ネヒ
+4,1000ネヒメヤノマ

+ 2 - 0
data/38.工作性质.csv

@@ -0,0 +1,2 @@
+1,全职
+2,实习

+ 7 - 0
data/39.薪资待遇.csv

@@ -0,0 +1,7 @@
+1,2k以下
+2,2k-5k
+3,5k-10k
+4,10k-15k
+5,15k-25k
+6,25k-50k
+7,50k以上

+ 29 - 0
data/40.职位类别.csv

@@ -0,0 +1,29 @@
+01,计算机/网络/技术类
+02,电子/电器/通信技术类
+03,行政/后勤类
+04,翻译类
+05,销售类
+06,客户服务类
+07,市场/公关/媒介类
+08,咨询/顾问类
+14,技工类
+09,财务/审计/统计类
+10,人力资源类
+11,教育/培训类
+12,质量管理类
+13,美术/设计/创意类
+15,金融保险类
+16,贸易/物流/采购/运输类
+17,经营管理类
+18,商业零售类
+19,建筑/房地产/装饰装修/物业管理类
+20,法律类
+21,酒店/餐饮/旅游/服务类
+22,生物/制药/化工/环保类
+23,文体/影视/写作/媒体类
+24,机械/仪器仪表类
+25,科研类
+26,工厂生产类
+27,医疗卫生/美容保健类
+28,电气/能源/动力类
+29,其他类

+ 5 - 0
data/41.学历层次.csv

@@ -0,0 +1,5 @@
+0,不限学历
+1,专科及以上
+2,本科及以上
+3,硕士及以上
+4,博士

+ 17 - 0
ecosystem.config.js

@@ -0,0 +1,17 @@
+'use strict';
+
+const app = 'naf-code';
+module.exports = {
+  apps: [{
+    name: app, // 应用名称
+    script: './server.js', // 实际启动脚本
+    out: `./logs/${app}.log`,
+    error: `./logs/${app}.err`,
+    watch: [ // 监控变化的目录,一旦变化,自动重启
+      'app', 'config',
+    ],
+    env: {
+      NODE_ENV: 'production', // 环境参数,当前指定为生产环境
+    },
+  }],
+};

+ 80 - 0
import.js

@@ -0,0 +1,80 @@
+'use strict';
+
+const readline = require('readline');
+const fs = require('fs');
+// const iconv = require('iconv-lite');
+const AutoDetectDecoderStream = require('autodetect-decoder-stream');
+const MongoClient = require('mongodb').MongoClient;
+
+// Connection URL
+// const url = 'mongodb://root:Ziyouyanfa%23%40!@localhost:27017';
+// const url = 'mongodb://root:Ziyouyanfa%23%40!@192.168.18.100:27018';
+const url = 'mongodb://root:Ziyouyanfa%23%40!@192.168.1.170:27018';
+
+// Database Name
+const dbName = 'naf';
+
+
+async function doWork() {
+  const args = process.argv.splice(2);
+  if (args.length !== 2) {
+    console.log('请指定要导入的文件名和类别:\n node import.js xxxx.csv 31');
+    return;
+  }
+  const category = args[1];
+
+  console.log(`正在读取${args[0]}数据...`);
+  const lines = await new Promise((resolve, reject) => {
+    const res = [];
+    const rl = readline.createInterface({
+      // input: fs.createReadStream(args[0]).pipe(iconv.decodeStream('GBK')),
+      // TODO: 自动检测编码
+      input: fs.createReadStream(args[0]).pipe(new AutoDetectDecoderStream({ defaultEncoding: 'GBK' })),
+      crlfDelay: Infinity,
+    });
+
+    rl.on('line', async line => {
+      // console.log(line);
+      res.push(line);
+    });
+    rl.on('close', () => {
+      resolve(res);
+    });
+    rl.on('error', err => {
+      reject(err);
+    });
+  });
+  console.log(`共读取数据${lines.length}条!`);
+  console.log('正在保存数据...');
+  // Use connect method to connect to the Server
+  const client = await MongoClient.connect(url, { poolSize: 10, useNewUrlParser: true });
+  const db = client.db(dbName).collection('naf_code_items');
+  let count = 0;
+  for (let i = 0; i < lines.length; i++) {
+    const line = lines[i];
+    const cols = line.split(',');
+    if (cols.length < 2) continue;
+    const data = { code: cols[0], name: cols[1], category, group: '0', stauts: '0', order: 0 };
+
+    console.log(line);
+    try {
+      const entity = await db.findOne({ code: cols[0], category });
+      if (!entity) {
+        await db.insertOne(data);
+        count++;
+      } else {
+        await db.updateOne({ _id: entity._id }, { $set: data });
+        console.log(`update: ${line}`);
+      }
+    } catch (err) {
+      console.log(`处理错误: ${line}`);
+      console.error(err);
+    }
+  }
+  if (client) {
+    client.close();
+  }
+  console.log(`导入完成,共导入${count}条数据!`);
+}
+
+doWork();

+ 80 - 0
import_unit.js

@@ -0,0 +1,80 @@
+'use strict';
+
+const readline = require('readline');
+const fs = require('fs');
+// const iconv = require('iconv-lite');
+const AutoDetectDecoderStream = require('autodetect-decoder-stream');
+const MongoClient = require('mongodb').MongoClient;
+
+// Connection URL
+// const url = 'mongodb://root:Ziyouyanfa%23%40!@localhost:27017';
+const url = 'mongodb://root:Ziyouyanfa%23%40!@192.168.18.100:27018';
+// const url = 'mongodb://root:Ziyouyanfa%23%40!@192.168.1.170:27018';
+
+// Database Name
+const dbName = 'naf';
+
+
+async function doWork() {
+  const args = process.argv.splice(2);
+  if (args.length !== 1) {
+    console.log('请指定要导入的文件名:\n node import.js xxxx.csv');
+    return;
+  }
+
+  console.log(`正在读取${args[0]}数据...`);
+  const lines = await new Promise((resolve, reject) => {
+    const res = [];
+    const rl = readline.createInterface({
+      // input: fs.createReadStream(args[0]).pipe(iconv.decodeStream('GBK')),
+      // TODO: 自动检测编码
+      input: fs.createReadStream(args[0]).pipe(new AutoDetectDecoderStream({ defaultEncoding: 'GBK' })),
+      crlfDelay: Infinity,
+    });
+
+    rl.on('line', async line => {
+      // console.log(line);
+      res.push(line);
+    });
+    rl.on('close', () => {
+      resolve(res);
+    });
+    rl.on('error', err => {
+      reject(err);
+    });
+  });
+  console.log(`共读取数据${lines.length}条!`);
+  console.log('正在保存数据...');
+  // Use connect method to connect to the Server
+  const client = await MongoClient.connect(url, { poolSize: 10 });
+  // const db = client.db(dbName).collection('naf_code_items');
+  const db = client.db(dbName).collection('naf_unit');
+  let count = 0;
+  for (let i = 0; i < lines.length; i++) {
+    const line = lines[i];
+    const cols = line.split(',');
+    if (cols.length < 2) continue;
+    const data = { code: cols[0], name: cols[1], createdAt: new Date(), updatedAt: new Date(), __v: 0 };
+
+    console.log(line);
+    try {
+      const entity = await db.findOne({ code: cols[0] });
+      if (!entity) {
+        await db.insertOne(data);
+        count++;
+      } else {
+        await db.updateOne({ _id: entity._id }, { $set: data });
+        console.log(`update: ${line}`);
+      }
+    } catch (err) {
+      console.log(`处理错误: ${line}`);
+      console.error(err);
+    }
+  }
+  if (client) {
+    client.close();
+  }
+  console.log(`导入完成,共导入${count}条数据!`);
+}
+
+doWork();

+ 51 - 0
package.json

@@ -0,0 +1,51 @@
+{
+  "name": "naf-code",
+  "version": "1.0.0",
+  "description": "NAF框架数据字典服务",
+  "private": true,
+  "egg": {
+    "framework": "naf-framework-mongoose"
+  },
+  "dependencies": {
+    "autodetect-decoder-stream": "^1.0.3",
+    "lodash": "^4.17.11",
+    "naf-framework-mongoose": "^0.6.1",
+    "xlsx": "^0.14.1"
+  },
+  "devDependencies": {
+    "autod": "^3.0.1",
+    "autod-egg": "^1.1.0",
+    "egg-bin": "^4.12.0",
+    "egg-ci": "^1.11.0",
+    "egg-mock": "^3.22.1",
+    "eslint": "^5.15.3",
+    "eslint-config-egg": "^7.2.0",
+    "eslint-config-egg-naf": "0.0.3"
+  },
+  "engines": {
+    "node": ">=8.9.0"
+  },
+  "scripts": {
+    "start": "egg-scripts start --daemon --title=naf-code",
+    "stop": "egg-scripts stop --title=naf-code",
+    "dev": "egg-bin dev",
+    "debug": "egg-bin debug",
+    "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",
+    "autod": "autod",
+    "pm2": "pm2 start",
+    "restart": "pm2 restart naf-code"
+  },
+  "ci": {
+    "version": "8"
+  },
+  "repository": {
+    "type": "git",
+    "url": ""
+  },
+  "author": "dyg",
+  "license": "MIT"
+}

+ 9 - 0
server.js

@@ -0,0 +1,9 @@
+
+// eslint-disable-next-line strict
+const egg = require('egg');
+
+const workers = Number(process.argv[2] || require('os').cpus().length);
+egg.startCluster({
+  workers,
+  baseDir: __dirname,
+});

+ 21 - 0
test/app/controller/home.test.js

@@ -0,0 +1,21 @@
+'use strict';
+
+const { app, assert } = require('egg-mock/bootstrap');
+
+describe('test/app/controller/home.test.js', () => {
+
+  it('should assert', function* () {
+    const pkg = require('../../../package.json');
+    assert(app.config.keys.startsWith(pkg.name));
+
+    // const ctx = app.mockContext({});
+    // yield ctx.service.xx();
+  });
+
+  it('should GET /', () => {
+    return app.httpRequest()
+      .get('/')
+      .expect('hi, egg')
+      .expect(200);
+  });
+});

+ 33 - 0
test/http/api.http

@@ -0,0 +1,33 @@
+###
+# 按类型检索list
+GET http://localhost:7001/code/32/list HTTP/1.1
+#GET http://oa.chinahuian.cn/naf/code/mz/list HTTP/1.1
+Accept: application/json
+
+###
+# 按类型和分组检索list
+GET http://localhost:7001/code/T01/0/list HTTP/1.1
+Accept: application/json
+
+###
+# 按类型检索fetch
+GET http://localhost:7001/code/32/fetch?code=1 HTTP/1.1
+#GET http://oa.chinahuian.cn/naf/code/mz/fetch?code=1 HTTP/1.1
+Accept: application/json
+
+###
+# 按类型和分组检索fetch
+GET http://localhost:7001/code/01/0/fetch?code=0 HTTP/1.1
+Accept: application/json
+
+###
+# 获取省列表
+#GET http://localhost:7001/code/xzqh/list?parent=000000&level=1 HTTP/1.1
+GET http://oa.chinahuian.cn/naf/code/xzqh/list?parent=000000&level=1 HTTP/1.1
+Accept: application/json
+
+###
+# 获取市列表
+#GET http://localhost:7001/code/xzqh/list?parent=220000&level=2 HTTP/1.1
+GET http://oa.chinahuian.cn/naf/code/xzqh/list?parent=220000&level=2 HTTP/1.1
+Accept: application/json

+ 50 - 0
test/http/category.http

@@ -0,0 +1,50 @@
+###字典类别
+# 创建字典类别
+POST http://localhost:7001/category/create HTTP/1.1
+#POST http://oa.chinahuian.cn/naf/code/category/create HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+{
+    "code": "32",
+    "name": "民族",
+    "key": "mz",
+    "order": 0
+}
+
+###
+# 删除字典类别
+POST http://localhost:7001/category/delete?code=T01 HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+###
+# 清空字典数据
+GET http://localhost:7001/items/T01/clear HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+
+###
+# fetch
+GET http://localhost:7001/category/fetch?_id=5a72371b3a4874300450c88c HTTP/1.1
+Accept: application/json
+
+
+
+###
+# list
+GET http://localhost:7001/category/list HTTP/1.1
+Accept: application/json
+
+
+###
+# 修改字典类别
+#POST  http://localhost:7001/category/update?code=31 HTTP/1.1
+POST  http://oa.chinahuian.cn/naf/code/category/update?code=31 HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+{
+    "key": "xzqh"
+}

+ 40 - 0
test/http/items.http

@@ -0,0 +1,40 @@
+#字典项
+##添加字典项
+POST http://localhost:7001/items/T01/create HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+{
+    "code": "1",
+    "name": "挂起"
+}
+
+###
+##删除字典数据
+POST http://localhost:7001/items/T01/delete?code=2 HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+###
+# update
+
+POST  http://localhost:7001/items/T01/update?code=1 HTTP/1.1
+content-type: application/json
+Accept: application/json
+
+{
+    "name": "挂起",
+    "order": 10
+}
+
+###
+# fetch
+GET http://localhost:7001/items/T01/fetch?code=2 HTTP/1.1
+Accept: application/json
+
+
+###
+# list
+GET http://localhost:7001/items/T01/list HTTP/1.1
+Accept: application/json
+

BIN
test/http/字典服务接口测试.rar