lrf 9 ヶ月 前
コミット
6002d1a094

BIN
importData/20240624/供应库.xlsx


BIN
importData/20240624/重点企业库.xlsx


BIN
importData/20240624/需求库.xlsx


BIN
importData/20240624/项目库.xlsx


ファイルの差分が大きいため隠しています
+ 2979 - 0
importData/area/CN_areas_2023.csv


+ 343 - 0
importData/area/CN_cities_2023.csv

@@ -0,0 +1,343 @@
+code,name,provinceCode
+1101,"市辖区",11
+1201,"市辖区",12
+1301,"石家庄市",13
+1302,"唐山市",13
+1303,"秦皇岛市",13
+1304,"邯郸市",13
+1305,"邢台市",13
+1306,"保定市",13
+1307,"张家口市",13
+1308,"承德市",13
+1309,"沧州市",13
+1310,"廊坊市",13
+1311,"衡水市",13
+1401,"太原市",14
+1402,"大同市",14
+1403,"阳泉市",14
+1404,"长治市",14
+1405,"晋城市",14
+1406,"朔州市",14
+1407,"晋中市",14
+1408,"运城市",14
+1409,"忻州市",14
+1410,"临汾市",14
+1411,"吕梁市",14
+1501,"呼和浩特市",15
+1502,"包头市",15
+1503,"乌海市",15
+1504,"赤峰市",15
+1505,"通辽市",15
+1506,"鄂尔多斯市",15
+1507,"呼伦贝尔市",15
+1508,"巴彦淖尔市",15
+1509,"乌兰察布市",15
+1522,"兴安盟",15
+1525,"锡林郭勒盟",15
+1529,"阿拉善盟",15
+2101,"沈阳市",21
+2102,"大连市",21
+2103,"鞍山市",21
+2104,"抚顺市",21
+2105,"本溪市",21
+2106,"丹东市",21
+2107,"锦州市",21
+2108,"营口市",21
+2109,"阜新市",21
+2110,"辽阳市",21
+2111,"盘锦市",21
+2112,"铁岭市",21
+2113,"朝阳市",21
+2114,"葫芦岛市",21
+2201,"长春市",22
+2202,"吉林市",22
+2203,"四平市",22
+2204,"辽源市",22
+2205,"通化市",22
+2206,"白山市",22
+2207,"松原市",22
+2208,"白城市",22
+2224,"延边朝鲜族自治州",22
+2301,"哈尔滨市",23
+2302,"齐齐哈尔市",23
+2303,"鸡西市",23
+2304,"鹤岗市",23
+2305,"双鸭山市",23
+2306,"大庆市",23
+2307,"伊春市",23
+2308,"佳木斯市",23
+2309,"七台河市",23
+2310,"牡丹江市",23
+2311,"黑河市",23
+2312,"绥化市",23
+2327,"大兴安岭地区",23
+3101,"市辖区",31
+3201,"南京市",32
+3202,"无锡市",32
+3203,"徐州市",32
+3204,"常州市",32
+3205,"苏州市",32
+3206,"南通市",32
+3207,"连云港市",32
+3208,"淮安市",32
+3209,"盐城市",32
+3210,"扬州市",32
+3211,"镇江市",32
+3212,"泰州市",32
+3213,"宿迁市",32
+3301,"杭州市",33
+3302,"宁波市",33
+3303,"温州市",33
+3304,"嘉兴市",33
+3305,"湖州市",33
+3306,"绍兴市",33
+3307,"金华市",33
+3308,"衢州市",33
+3309,"舟山市",33
+3310,"台州市",33
+3311,"丽水市",33
+3401,"合肥市",34
+3402,"芜湖市",34
+3403,"蚌埠市",34
+3404,"淮南市",34
+3405,"马鞍山市",34
+3406,"淮北市",34
+3407,"铜陵市",34
+3408,"安庆市",34
+3410,"黄山市",34
+3411,"滁州市",34
+3412,"阜阳市",34
+3413,"宿州市",34
+3415,"六安市",34
+3416,"亳州市",34
+3417,"池州市",34
+3418,"宣城市",34
+3501,"福州市",35
+3502,"厦门市",35
+3503,"莆田市",35
+3504,"三明市",35
+3505,"泉州市",35
+3506,"漳州市",35
+3507,"南平市",35
+3508,"龙岩市",35
+3509,"宁德市",35
+3601,"南昌市",36
+3602,"景德镇市",36
+3603,"萍乡市",36
+3604,"九江市",36
+3605,"新余市",36
+3606,"鹰潭市",36
+3607,"赣州市",36
+3608,"吉安市",36
+3609,"宜春市",36
+3610,"抚州市",36
+3611,"上饶市",36
+3701,"济南市",37
+3702,"青岛市",37
+3703,"淄博市",37
+3704,"枣庄市",37
+3705,"东营市",37
+3706,"烟台市",37
+3707,"潍坊市",37
+3708,"济宁市",37
+3709,"泰安市",37
+3710,"威海市",37
+3711,"日照市",37
+3713,"临沂市",37
+3714,"德州市",37
+3715,"聊城市",37
+3716,"滨州市",37
+3717,"菏泽市",37
+4101,"郑州市",41
+4102,"开封市",41
+4103,"洛阳市",41
+4104,"平顶山市",41
+4105,"安阳市",41
+4106,"鹤壁市",41
+4107,"新乡市",41
+4108,"焦作市",41
+4109,"濮阳市",41
+4110,"许昌市",41
+4111,"漯河市",41
+4112,"三门峡市",41
+4113,"南阳市",41
+4114,"商丘市",41
+4115,"信阳市",41
+4116,"周口市",41
+4117,"驻马店市",41
+4190,"直辖县",41
+4201,"武汉市",42
+4202,"黄石市",42
+4203,"十堰市",42
+4205,"宜昌市",42
+4206,"襄阳市",42
+4207,"鄂州市",42
+4208,"荆门市",42
+4209,"孝感市",42
+4210,"荆州市",42
+4211,"黄冈市",42
+4212,"咸宁市",42
+4213,"随州市",42
+4228,"恩施土家族苗族自治州",42
+4290,"直辖县",42
+4301,"长沙市",43
+4302,"株洲市",43
+4303,"湘潭市",43
+4304,"衡阳市",43
+4305,"邵阳市",43
+4306,"岳阳市",43
+4307,"常德市",43
+4308,"张家界市",43
+4309,"益阳市",43
+4310,"郴州市",43
+4311,"永州市",43
+4312,"怀化市",43
+4313,"娄底市",43
+4331,"湘西土家族苗族自治州",43
+4401,"广州市",44
+4402,"韶关市",44
+4403,"深圳市",44
+4404,"珠海市",44
+4405,"汕头市",44
+4406,"佛山市",44
+4407,"江门市",44
+4408,"湛江市",44
+4409,"茂名市",44
+4412,"肇庆市",44
+4413,"惠州市",44
+4414,"梅州市",44
+4415,"汕尾市",44
+4416,"河源市",44
+4417,"阳江市",44
+4418,"清远市",44
+4419,"东莞市",44
+4420,"中山市",44
+4451,"潮州市",44
+4452,"揭阳市",44
+4453,"云浮市",44
+4501,"南宁市",45
+4502,"柳州市",45
+4503,"桂林市",45
+4504,"梧州市",45
+4505,"北海市",45
+4506,"防城港市",45
+4507,"钦州市",45
+4508,"贵港市",45
+4509,"玉林市",45
+4510,"百色市",45
+4511,"贺州市",45
+4512,"河池市",45
+4513,"来宾市",45
+4514,"崇左市",45
+4601,"海口市",46
+4602,"三亚市",46
+4603,"三沙市",46
+4604,"儋州市",46
+4690,"直辖县",46
+5001,"市辖区",50
+5002,"县",50
+5101,"成都市",51
+5103,"自贡市",51
+5104,"攀枝花市",51
+5105,"泸州市",51
+5106,"德阳市",51
+5107,"绵阳市",51
+5108,"广元市",51
+5109,"遂宁市",51
+5110,"内江市",51
+5111,"乐山市",51
+5113,"南充市",51
+5114,"眉山市",51
+5115,"宜宾市",51
+5116,"广安市",51
+5117,"达州市",51
+5118,"雅安市",51
+5119,"巴中市",51
+5120,"资阳市",51
+5132,"阿坝藏族羌族自治州",51
+5133,"甘孜藏族自治州",51
+5134,"凉山彝族自治州",51
+5201,"贵阳市",52
+5202,"六盘水市",52
+5203,"遵义市",52
+5204,"安顺市",52
+5205,"毕节市",52
+5206,"铜仁市",52
+5223,"黔西南布依族苗族自治州",52
+5226,"黔东南苗族侗族自治州",52
+5227,"黔南布依族苗族自治州",52
+5301,"昆明市",53
+5303,"曲靖市",53
+5304,"玉溪市",53
+5305,"保山市",53
+5306,"昭通市",53
+5307,"丽江市",53
+5308,"普洱市",53
+5309,"临沧市",53
+5323,"楚雄彝族自治州",53
+5325,"红河哈尼族彝族自治州",53
+5326,"文山壮族苗族自治州",53
+5328,"西双版纳傣族自治州",53
+5329,"大理白族自治州",53
+5331,"德宏傣族景颇族自治州",53
+5333,"怒江傈僳族自治州",53
+5334,"迪庆藏族自治州",53
+5401,"拉萨市",54
+5402,"日喀则市",54
+5403,"昌都市",54
+5404,"林芝市",54
+5405,"山南市",54
+5406,"那曲市",54
+5425,"阿里地区",54
+6101,"西安市",61
+6102,"铜川市",61
+6103,"宝鸡市",61
+6104,"咸阳市",61
+6105,"渭南市",61
+6106,"延安市",61
+6107,"汉中市",61
+6108,"榆林市",61
+6109,"安康市",61
+6110,"商洛市",61
+6201,"兰州市",62
+6202,"嘉峪关市",62
+6203,"金昌市",62
+6204,"白银市",62
+6205,"天水市",62
+6206,"武威市",62
+6207,"张掖市",62
+6208,"平凉市",62
+6209,"酒泉市",62
+6210,"庆阳市",62
+6211,"定西市",62
+6212,"陇南市",62
+6229,"临夏回族自治州",62
+6230,"甘南藏族自治州",62
+6301,"西宁市",63
+6302,"海东市",63
+6322,"海北藏族自治州",63
+6323,"黄南藏族自治州",63
+6325,"海南藏族自治州",63
+6326,"果洛藏族自治州",63
+6327,"玉树藏族自治州",63
+6328,"海西蒙古族藏族自治州",63
+6401,"银川市",64
+6402,"石嘴山市",64
+6403,"吴忠市",64
+6404,"固原市",64
+6405,"中卫市",64
+6501,"乌鲁木齐市",65
+6502,"克拉玛依市",65
+6504,"吐鲁番市",65
+6505,"哈密市",65
+6523,"昌吉回族自治州",65
+6527,"博尔塔拉蒙古自治州",65
+6528,"巴音郭楞蒙古自治州",65
+6529,"阿克苏地区",65
+6530,"克孜勒苏柯尔克孜自治州",65
+6531,"喀什地区",65
+6532,"和田地区",65
+6540,"伊犁哈萨克自治州",65
+6542,"塔城地区",65
+6543,"阿勒泰地区",65
+6590,"直辖县",65

+ 32 - 0
importData/area/CN_provinces_2023.csv

@@ -0,0 +1,32 @@
+code,name
+11,"北京市"
+12,"天津市"
+13,"河北省"
+14,"山西省"
+15,"内蒙古自治区"
+21,"辽宁省"
+22,"吉林省"
+23,"黑龙江省"
+31,"上海市"
+32,"江苏省"
+33,"浙江省"
+34,"安徽省"
+35,"福建省"
+36,"江西省"
+37,"山东省"
+41,"河南省"
+42,"湖北省"
+43,"湖南省"
+44,"广东省"
+45,"广西壮族自治区"
+46,"海南省"
+50,"重庆市"
+51,"四川省"
+52,"贵州省"
+53,"云南省"
+54,"西藏自治区"
+61,"陕西省"
+62,"甘肃省"
+63,"青海省"
+64,"宁夏回族自治区"
+65,"新疆维吾尔自治区"

ファイルの差分が大きいため隠しています
+ 41353 - 0
importData/area/CN_streets_2023.csv


+ 121 - 0
package-lock.json

@@ -9,6 +9,7 @@
       "version": "1.0.0",
       "license": "MIT",
       "dependencies": {
+        "@elastic/elasticsearch": "^8.12.2",
         "@midwayjs/bootstrap": "^3.12.0",
         "@midwayjs/core": "^3.12.0",
         "@midwayjs/info": "^3.12.0",
@@ -608,6 +609,49 @@
       "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
       "dev": true
     },
+    "node_modules/@elastic/elasticsearch": {
+      "version": "8.12.2",
+      "resolved": "https://registry.npmmirror.com/@elastic/elasticsearch/-/elasticsearch-8.12.2.tgz",
+      "integrity": "sha512-04NvH3LIgcv1Uwguorfw2WwzC9Lhfsqs9f0L6uq6MrCw0lqe/HOQ6E8vJ6EkHAA15iEfbhtxOtenbZVVcE+mAQ==",
+      "dependencies": {
+        "@elastic/transport": "^8.4.1",
+        "tslib": "^2.4.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@elastic/elasticsearch/node_modules/tslib": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.3.tgz",
+      "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
+    },
+    "node_modules/@elastic/transport": {
+      "version": "8.6.0",
+      "resolved": "https://registry.npmmirror.com/@elastic/transport/-/transport-8.6.0.tgz",
+      "integrity": "sha512-/Ucpztrc+urZK8yCtFBUu2LePYJNnukgZSUUApUzGH/SxejqkH526Nph7aru8I0vZwdW5wqgCHSOIq3J7tIxGg==",
+      "dependencies": {
+        "debug": "^4.3.4",
+        "hpagent": "^1.0.0",
+        "ms": "^2.1.3",
+        "secure-json-parse": "^2.4.0",
+        "tslib": "^2.4.0",
+        "undici": "^6.12.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@elastic/transport/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+    },
+    "node_modules/@elastic/transport/node_modules/tslib": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.3.tgz",
+      "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
+    },
     "node_modules/@eslint-community/eslint-utils": {
       "version": "4.4.0",
       "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -4837,6 +4881,14 @@
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "node_modules/hpagent": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/hpagent/-/hpagent-1.2.0.tgz",
+      "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==",
+      "engines": {
+        "node": ">=14"
+      }
+    },
     "node_modules/html-escaper": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -8058,6 +8110,11 @@
       "resolved": "https://registry.npmmirror.com/scmp/-/scmp-2.1.0.tgz",
       "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
     },
+    "node_modules/secure-json-parse": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmmirror.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+      "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
+    },
     "node_modules/semver": {
       "version": "6.3.1",
       "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
@@ -8989,6 +9046,14 @@
         "node": ">=4.2.0"
       }
     },
+    "node_modules/undici": {
+      "version": "6.19.1",
+      "resolved": "https://registry.npmmirror.com/undici/-/undici-6.19.1.tgz",
+      "integrity": "sha512-m9QbEf5+YWXYycRHQtE22hTmRv2R6IDpBVR9UuHKvrDZJxrpgqnKkdV5inOdFskVxz3DmcKhDY/B1sE+ShhopQ==",
+      "engines": {
+        "node": ">=18.17"
+      }
+    },
     "node_modules/unique-string": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz",
@@ -9839,6 +9904,47 @@
       "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
       "dev": true
     },
+    "@elastic/elasticsearch": {
+      "version": "8.12.2",
+      "resolved": "https://registry.npmmirror.com/@elastic/elasticsearch/-/elasticsearch-8.12.2.tgz",
+      "integrity": "sha512-04NvH3LIgcv1Uwguorfw2WwzC9Lhfsqs9f0L6uq6MrCw0lqe/HOQ6E8vJ6EkHAA15iEfbhtxOtenbZVVcE+mAQ==",
+      "requires": {
+        "@elastic/transport": "^8.4.1",
+        "tslib": "^2.4.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.3.tgz",
+          "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
+        }
+      }
+    },
+    "@elastic/transport": {
+      "version": "8.6.0",
+      "resolved": "https://registry.npmmirror.com/@elastic/transport/-/transport-8.6.0.tgz",
+      "integrity": "sha512-/Ucpztrc+urZK8yCtFBUu2LePYJNnukgZSUUApUzGH/SxejqkH526Nph7aru8I0vZwdW5wqgCHSOIq3J7tIxGg==",
+      "requires": {
+        "debug": "^4.3.4",
+        "hpagent": "^1.0.0",
+        "ms": "^2.1.3",
+        "secure-json-parse": "^2.4.0",
+        "tslib": "^2.4.0",
+        "undici": "^6.12.0"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+        },
+        "tslib": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.3.tgz",
+          "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
+        }
+      }
+    },
     "@eslint-community/eslint-utils": {
       "version": "4.4.0",
       "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@@ -13029,6 +13135,11 @@
         }
       }
     },
+    "hpagent": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/hpagent/-/hpagent-1.2.0.tgz",
+      "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA=="
+    },
     "html-escaper": {
       "version": "2.0.2",
       "resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -15467,6 +15578,11 @@
       "resolved": "https://registry.npmmirror.com/scmp/-/scmp-2.1.0.tgz",
       "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
     },
+    "secure-json-parse": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmmirror.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+      "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
+    },
     "semver": {
       "version": "6.3.1",
       "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz",
@@ -16097,6 +16213,11 @@
       "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
       "dev": true
     },
+    "undici": {
+      "version": "6.19.1",
+      "resolved": "https://registry.npmmirror.com/undici/-/undici-6.19.1.tgz",
+      "integrity": "sha512-m9QbEf5+YWXYycRHQtE22hTmRv2R6IDpBVR9UuHKvrDZJxrpgqnKkdV5inOdFskVxz3DmcKhDY/B1sE+ShhopQ=="
+    },
     "unique-string": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz",

+ 1 - 0
package.json

@@ -4,6 +4,7 @@
   "description": "",
   "private": true,
   "dependencies": {
+    "@elastic/elasticsearch": "^8.12.2",
     "@midwayjs/bootstrap": "^3.12.0",
     "@midwayjs/core": "^3.12.0",
     "@midwayjs/info": "^3.12.0",

+ 1 - 1
src/config/config.self.ts

@@ -63,7 +63,7 @@ export default {
         port: 54321,
         entities: ['./entityLogs'],
         type: 'postgres',
-        synchronize: true, // 如果第一次使用,不存在表,有同步的需求可以写 true,注意会丢数据
+        synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true,注意会丢数据
         logging: false,
       },
     },

+ 7 - 3
src/controller/home.controller.ts

@@ -1,14 +1,18 @@
 import { Controller, Get, Inject } from '@midwayjs/core';
-import { UtilService } from '../service/util.service';
+import { initTwoService } from '../service/initData/initTwo.service';
+import { InitRegionService } from '../service/initData/initRegion.service';
 
 @Controller('/')
 export class HomeController {
   @Inject()
-  service: UtilService;
+  service: initTwoService;
+  @Inject()
+  regionService: InitRegionService
   @Get('/')
   async home(): Promise<any> {
     // const result: any = await this.adminService.create();
-    const res = await this.service.DBTransaction();
+    const res = await this.service.initData();
+    // const res = await this.regionService.index();
     return res;
     // return 'starting...';
   }

+ 24 - 0
src/controller/log/opera.controller.ts

@@ -0,0 +1,24 @@
+import { Controller, Get, Inject, Param, Query } from '@midwayjs/core';
+import { OperaService } from '../../service/log/opera.service';
+import { omit, pick } from 'lodash';
+const namePrefix = '操作日志';
+@Controller('/log/opera')
+export class OperaController {
+  @Inject()
+  service: OperaService;
+  @Get('/', { routerName: `查询${namePrefix}` })
+  async index(@Query() query: object) {
+    const qobj = omit(query, ['skip', 'limit']);
+    const others = pick(query, ['skip', 'limit']);
+    const qbr = this.service.queryBuilder(qobj);
+    const result = await this.service.query(qbr, others);
+    return result;
+  }
+
+  @Get('/:id', { routerName: `创建${namePrefix}` })
+  async fetch(@Param('id') id: number) {
+    const qbr = this.service.queryBuilder({ id });
+    const data = await this.service.fetch(qbr);
+    return data;
+  }
+}

+ 11 - 0
src/entity/platform/demand.entity.ts

@@ -30,12 +30,23 @@ export class Demand extends BaseModel {
   @Column({ type: 'character varying', nullable: true, comment: '状态' })
   status: string;
 
+  @Column({ type: 'character varying', nullable: true, comment: '所属产业' })
+  industry: string;
   @Column({ type: 'character varying', nullable: true, comment: '所属企业' })
   company: string;
+  @Column({ type: 'character varying', nullable: true, comment: '企业简况' })
+  company_brief: string;
   @Column({ type: 'character varying', nullable: true, comment: '联系人' })
   contacts: string;
   @Column({ type: 'character varying', nullable: true, comment: '联系电话' })
   tel: string;
   @Column({ type: 'character varying', nullable: true, comment: '年份' })
   year: string;
+  @Column({ type: 'character varying', nullable: true, comment: '月份' })
+  month: string;
+  @Column({ type: 'character varying', nullable: true, comment: '技术需求名称' })
+  tec_name: string;
+  @Column({ type: 'character varying', nullable: true, comment: '待解决问题' })
+  question: string;
+  
 }

+ 11 - 0
src/entity/platform/project.entity.ts

@@ -27,4 +27,15 @@ export class Project extends BaseModel {
   is_use: string;
   @Column({ type: 'character varying', nullable: true, comment: '状态' })
   status: string;
+
+  @Column({ type: 'character varying', nullable: true, comment: '项目主体' })
+  main: string;
+  @Column({ type: 'character varying', nullable: true, comment: '项目进展' })
+  progress: string;
+  @Column({ type: 'character varying', nullable: true, comment: '跟踪支持单位' })
+  track_unit: string;
+  @Column({ type: 'character varying', nullable: true, comment: '项目来源' })
+  source: string;
+  @Column({ type: 'character varying', nullable: true, comment: '产业分类' })
+  industry: string;
 }

+ 7 - 1
src/entity/platform/supply.entity.ts

@@ -19,7 +19,7 @@ export class Supply extends BaseModel {
   time: Array<any>;
   @Column({ type: 'character varying', nullable: true, comment: '价格' })
   money: string;
-  @Column({ type: 'jsonb', nullable: true, comment: '需求地区' })
+  @Column({ type: 'jsonb', nullable: true, comment: '供给地区' })
   area: Array<any>;
   @Column({ type: 'text', nullable: true, comment: '简介' })
   brief: string;
@@ -29,4 +29,10 @@ export class Supply extends BaseModel {
   is_use: string;
   @Column({ type: 'character varying', nullable: true, comment: '状态' })
   status: string;
+
+  @Column({ type: 'character varying', nullable: true, comment: '所属产业' })
+  industry: string;
+
+  @Column({ type: 'character varying', nullable: true, comment: '项目来源' })
+  source: string;
 }

+ 14 - 0
src/entity/system/region.entity.ts

@@ -0,0 +1,14 @@
+import { Entity, Column } from 'typeorm';
+import { BaseModel } from '../../frame/BaseModel';
+
+@Entity('region')
+export class Region extends BaseModel {
+  @Column({ type: 'character varying', nullable: true, comment: '编码' })
+  code: string;
+  @Column({ type: 'character varying', nullable: true, comment: '名称' })
+  name: string;
+  @Column({ type: 'character varying', nullable: true, comment: '上级编码' })
+  parent_code: string;
+  @Column({ type: 'character varying', nullable: true, comment: '等级:province;city;area;street' })
+  level: string;
+}

+ 3 - 0
src/entity/users/company.entity.ts

@@ -44,4 +44,7 @@ export class Company extends BaseModel {
   companyStatus: string;
   @Column({ type: 'character varying', default: '0', comment: '状态' })
   status: string;
+
+  @Column({ type: 'character varying', nullable: true, comment: '是否公开' })
+  products: string;
 }

+ 240 - 0
src/service/initData/initOne.service.ts

@@ -0,0 +1,240 @@
+import { Provide } from "@midwayjs/core";
+import { InjectEntityModel } from "@midwayjs/typeorm";
+import { isArray } from "lodash";
+import { Repository } from "typeorm";
+import { Achievement } from "../../entity/platform/achievement.entity";
+import { Demand } from "../../entity/platform/demand.entity";
+import { Expert } from "../../entity/users/expert.entity";
+import * as Excel from 'exceljs';
+// 2024-06-11 导入
+@Provide()
+export class initOneService {
+  @InjectEntityModel(Demand)
+  demandModel: Repository<Demand>;
+  @InjectEntityModel(Achievement)
+  achievementModel: Repository<Achievement>;
+  @InjectEntityModel(Expert)
+  expertModel: Repository<Expert>;
+  async initData() {
+    console.log('in initData');
+    await this.importRequirementFromExcel();
+    // await this.importAchieveFromExcel();
+    // await this.importExpertFromExcel();
+  }
+  async importRequirementFromExcel() {
+    const path = 'C:/document/需求库.xlsx';
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(path);
+    const sheet = wb.getWorksheet(1);
+    const meta = this.requirementMeta();
+    const allData = [];
+    const cityArr = ['长春', '吉林', '通化', '白山', '辽源', '四平', '白城', '松原', '延边州', '延边'];
+    const areaArr = [
+      '五棵树经济开发区',
+      '南关区',
+      '宽城区',
+      '朝阳区',
+      '二道区',
+      '绿园区',
+      '双阳区',
+      '九台区',
+      '公主岭市',
+      '榆树市',
+      '德惠市',
+      '农安县',
+      '昌邑区',
+      '龙潭区',
+      '船营区',
+      '丰满区',
+      '蛟河市',
+      '桦甸市',
+      '舒兰市',
+      '磐石市',
+      '永吉县',
+      '东昌区',
+      '二道江区',
+      '集安市',
+      '梅河口市',
+      '通化县',
+      '辉南县',
+      '柳河县',
+      '浑江区',
+      '江源区',
+      '临江市',
+      '抚松县',
+      '靖宇县',
+      '长白朝鲜族自治县',
+      '龙山区',
+      '西安区',
+      '东丰县',
+      '东辽县',
+      '铁西区',
+      '铁东区',
+      '双辽市',
+      '梨树县',
+      '伊通满族自治县',
+      '洮北区',
+      '洮南市',
+      '大安市',
+      '镇赉县',
+      '通榆县',
+      '宁江区',
+      '扶余市',
+      '长岭县',
+      '乾安县',
+      '前郭尔罗斯蒙古族自治县',
+      '延吉市',
+      '图们市',
+      '敦化市',
+      '珲春市',
+      '龙井市',
+      '和龙市',
+      '汪清县',
+      '安图县',
+    ];
+    const specialList = [
+      { e: '高新区', to: '高新技术产业开发区' },
+      { e: '高新', to: '高新技术产业开发区' },
+      { e: '经开', to: '经济技术开发区' },
+      { e: '五棵树', to: '五棵树经济开发区' },
+      { e: '北湖', to: '北湖科技开发区' },
+      { e: '净月', to: '净月高新技术产业开发区' },
+      { e: '绿园经济', to: '绿园经济开发区' },
+    ];
+    const ignoreArea = ['吉林', '长春', '白城'];
+    const specialAreaList = [
+      { e: '梅河口', to: ['吉林省', '通化市', '梅河口市'] },
+      { e: '德惠', to: ['吉林省', '长春市', '德惠市'] },
+      { e: '敦化', to: ['吉林省', '延边州', '敦化市'] },
+      { e: '延吉', to: ['吉林省', '延边州', '延吉市'] },
+      { e: '柳河', to: ['吉林省', '通化市', '柳河县'] },
+    ];
+    sheet.eachRow((row, ri) => {
+      if (ri === 1 || ri === 2) {
+        // 不处理
+      } else {
+        const obj = {};
+        row.eachCell((cell, ci) => {
+          const val = cell.value as string;
+          const key = meta[ci];
+          if (ci === 3) {
+            let area = ['吉林省'];
+            // 处理地区
+            const res = cityArr.find(f => val.includes(f));
+            if (res) {
+              // 有市级关键词的, 延边州不需要处理
+              if (res === '延边') area.push('延边州');
+              else if (res !== '延边州') area.push(`${res}市`);
+              else area.push(res);
+              const elseStr = val.replace(res, '');
+              if (elseStr !== '' && !ignoreArea.includes(elseStr)) {
+                const areaVal = areaArr.find(f => f.includes(elseStr));
+                if (areaVal) area.push(areaVal);
+                else {
+                  const rs = specialList.find(f => elseStr.includes(f.e));
+                  if (rs) area.push(rs.to);
+                }
+              }
+            } else {
+              const res = specialAreaList.find(f => val.includes(f.e));
+              if (res) area = res.to;
+              else obj['no_area'] = true;
+            }
+            obj[key] = area;
+          } else if (ci === 6) {
+            // 分离人员和电话
+            const strReg = /([\u4e00-\u9fa5]{3}|[\u4e00-\u9fa5]{2})/g;
+            const strRes = val.match(strReg);
+            const numRes = val.replace(strReg, '').replace('\n', '');
+            if (isArray(strRes)) obj['contacts'] = strRes.join(';');
+            if (isArray(numRes)) obj['tel'] = numRes.join(';');
+            if (numRes) obj['tel'] = numRes;
+          } else if (key) obj[key] = val;
+        });
+        allData.push(obj);
+      }
+    });
+    const res = await this.demandModel.insert(allData);
+    return res;
+  }
+
+  requirementMeta() {
+    return {
+      2: 'field',
+      3: 'area',
+      4: 'company',
+      5: 'brief',
+      6: 'contacts',
+      7: 'year',
+    };
+  }
+
+  async importAchieveFromExcel() {
+    const path = 'C:/document/成果库.xlsx';
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(path);
+    const sheet = wb.getWorksheet(1);
+    const meta = this.achieveMeta();
+    const allData = [];
+    sheet.eachRow((row, ri) => {
+      if (ri === 1 || ri === 2) {
+        // 不处理
+      } else {
+        const obj = {};
+        row.eachCell((cell, ci) => {
+          const val = cell.value;
+          const key = meta[ci];
+          if (key) obj[key] = val;
+        });
+        allData.push(obj);
+      }
+    });
+    return await this.achievementModel.insert(allData);
+  }
+  achieveMeta() {
+    return {
+      2: 'field',
+      3: 'name',
+      4: 'brief',
+      5: 'source',
+      6: 'person',
+      7: 'tel',
+    };
+  }
+
+  async importExpertFromExcel() {
+    const path = 'C:/document/专家库.xlsx';
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(path);
+    const sheet = wb.getWorksheet(1);
+    const rows = sheet.getRows(3, 200);
+    const meta = this.exportsMeta();
+    const allData = [];
+    for (const row of rows) {
+      const obj = {};
+      row.eachCell((cell, index) => {
+        let val = cell.value as string;
+        if (index === 4) {
+          const varr = val.split('').filter(f => f !== ' ');
+          val = varr.join('');
+        }
+        const key = meta[index];
+        obj[key] = val;
+      });
+      allData.push(obj);
+    }
+    const res = await this.expertModel.insert(allData);
+    return res;
+  }
+
+  exportsMeta() {
+    return {
+      1: 'industry_type',
+      2: 'industry',
+      3: 'work_type',
+      4: 'name',
+      5: 'work',
+      6: 'title',
+    };
+  }
+}

+ 71 - 0
src/service/initData/initRegion.service.ts

@@ -0,0 +1,71 @@
+import { Provide } from '@midwayjs/core';
+import * as Excel from 'exceljs';
+import * as path from 'path';
+import { Region } from '../../entity/system/region.entity';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { Repository } from 'typeorm';
+@Provide()
+export class InitRegionService {
+  @InjectEntityModel(Region)
+  regionModel: Repository<Region>;
+  async index() {
+    // this.initProvnices();
+    // this.initNotProvnice('cities');
+    // this.initNotProvnice('areas');
+    // 街道数据量大,需要拆分
+    // this.initNotProvnice('streets');
+  }
+  async initProvnices() {
+    const p = path.resolve(__dirname, '../../../importData', 'area', 'CN_provinces_2023.csv');
+    const workbook = new Excel.Workbook();
+    const worksheet = await workbook.csv.readFile(p);
+    const meta = {
+      1: 'code',
+      2: 'name',
+    };
+    const allData = [];
+    worksheet.eachRow((row, ri) => {
+      if (ri === 1) {
+        // 不处理
+      } else {
+        const arr = row.values;
+        const obj = { level: 'province' };
+        for (const key in meta) {
+          obj[meta[key]] = arr[key];
+        }
+        allData.push(obj);
+      }
+    });
+    return await this.regionModel.insert(allData);
+  }
+
+  async initNotProvnice(type) {
+    const p = path.resolve(__dirname, '../../../importData', 'area', `CN_${type}_2023.csv`);
+    const workbook = new Excel.Workbook();
+    const worksheet = await workbook.csv.readFile(p);
+    const meta = {
+      1: 'code',
+      2: 'name',
+      3: 'parent_code',
+    };
+    const allData = [];
+    const levelObj = {
+      cities: 'city',
+      areas: 'area',
+      streets: 'street',
+    };
+    worksheet.eachRow((row, ri) => {
+      if (ri === 1) {
+        // 不处理
+      } else {
+        const arr = row.values;
+        const obj = { level: levelObj[type] };
+        for (const key in meta) {
+          obj[meta[key]] = arr[key];
+        }
+        allData.push(obj);
+      }
+    });
+    return await this.regionModel.insert(allData);
+  }
+}

+ 338 - 0
src/service/initData/initTwo.service.ts

@@ -0,0 +1,338 @@
+import { Provide } from '@midwayjs/core';
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import * as Excel from 'exceljs';
+import * as path from 'path';
+import { And, Equal, Like, Not, Repository } from 'typeorm';
+import { Region } from '../../entity/system/region.entity';
+import { Company } from '../../entity/users/company.entity';
+import { DictData } from '../../entity/system/dictData.entity';
+import { Supply } from '../../entity/platform/supply.entity';
+import { differenceWith, get, isEqual, isObject, isString, last, take, trim } from 'lodash';
+import { Demand } from '../../entity/platform/demand.entity';
+import _ = require('lodash');
+import { Project } from '../../entity/platform/project.entity';
+// 2024-06-24 导入
+@Provide()
+export class initTwoService {
+  @InjectEntityModel(Region)
+  regionModel: Repository<Region>;
+  @InjectEntityModel(Company)
+  companyModel: Repository<Company>;
+  @InjectEntityModel(DictData)
+  dictDataModel: Repository<DictData>;
+  @InjectEntityModel(Supply)
+  supplyModel: Repository<Supply>;
+  @InjectEntityModel(Demand)
+  demandModel: Repository<Demand>;
+  @InjectEntityModel(Project)
+  projectModel: Repository<Project>;
+
+  async initData() {
+    // return await this.importCompany();
+    // return await this.importSupply();
+    // return await this.importDemand();
+    return await this.importProject();
+  }
+  /**
+   * 获取excel表头对应的字段
+   * @returns 表格列对应字段对象
+   */
+  companyMeta() {
+    return {
+      2: 'area1',
+      3: 'area2',
+      4: 'name',
+      5: 'products',
+      6: 'type',
+      7: 'person',
+    };
+  }
+  async importCompany() {
+    const p = path.resolve(__dirname, '../../../importData/20240624', '重点企业库.xlsx');
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(p);
+    const sheet = wb.getWorksheet('总表');
+    if (!sheet) return;
+    const meta = this.companyMeta();
+    const specialDeal = {
+      新区: '新区',
+      高新区: '长春高新技术产业开发区',
+      经开: '长春经济技术开发区',
+      中韩: '中韩国际合作示范区',
+      汽开: '长春汽车经济技术开发区',
+      // 医药高新区: '',
+      // 中新食品区: '',
+    };
+    const allData = [];
+    sheet.eachRow((row, ri) => {
+      if (ri === 1 || ri === 2) {
+        // 不处理
+      } else {
+        const obj = {};
+        row.eachCell((cell, ci) => {
+          const val = cell.value;
+          const key = meta[ci];
+          if (key) obj[key] = val;
+        });
+        allData.push(obj);
+      }
+    });
+    // 需要处理下 area1和area2,这俩是需要放到 area中,在region中找到合适的数据后放到area []里
+    for (const i of allData) {
+      // #region 地区处理
+      i.area = ['吉林省'];
+      if (i.area2 === '医药高新区') {
+        i.area.push('通化市', '医药高新区');
+      } else if (i.area2 === '中新食品区') {
+        i.area.push('吉林市', '医药高新区');
+      } else {
+        const builder = this.regionModel.createQueryBuilder();
+        builder.where(`name like '%${i.area1}%'`);
+        // builder.andWhere(`name Not Like '%省%'`);
+        builder.andWhere(`level = 'city'`);
+        builder.andWhere(`code like '22%'`);
+        const r1 = await builder.getOne();
+        const r2 = await this.regionModel.findOne({ where: { name: Like(`%${i.area2}%`), code: Like('22%'), level: Equal('area') } });
+        if (r1) i.area.push(r1.name);
+        if (r2) i.area.push(r2.name);
+        else {
+          // 需要特殊处理的
+          const str = specialDeal[i.area2];
+          if (str) i.area.push(str);
+        }
+      }
+      delete i.area1;
+      delete i.area2;
+      // #endregion
+      // #region 字典处理
+      if (i.type === '农林牧渔业') {
+        i.type = '0';
+      } else if (i.type === '卫生和社会工作') {
+        i.type = '16';
+      } else {
+        const typeDict = await this.dictDataModel.findOne({ where: { label: i.type } });
+        if (typeDict) {
+          i.type = typeDict.value;
+        }
+      }
+      // #endregion
+    }
+    await this.companyModel.insert(allData);
+  }
+
+  supplyMeta() {
+    return {
+      3: 'industry',
+      4: 'field',
+      5: 'name',
+      6: 'brief',
+      7: 'source',
+    };
+  }
+
+  async importSupply() {
+    const p = path.resolve(__dirname, '../../../importData/20240624', '供应库.xlsx');
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(p);
+    const sheet = wb.getWorksheet('总库');
+    if (!sheet) return;
+    const meta = this.supplyMeta();
+    const allData = [];
+    sheet.eachRow((row, ri) => {
+      if (ri === 1 || ri === 2) {
+        // 不处理
+      } else {
+        const obj = {};
+        row.eachCell((cell, ci) => {
+          const val = cell.value;
+          const key = meta[ci];
+          if (key) obj[key] = val;
+        });
+        allData.push(obj);
+      }
+    });
+    // TODO:将产业,领域换成字典表
+
+    // return allData;
+    await this.supplyModel.insert(allData);
+  }
+
+  demandMeta() {
+    return {
+      4: 'industry',
+      5: 'field',
+      6: 'area1',
+      7: 'area2',
+      8: 'company',
+      9: 'tec_name',
+      10: 'company_brief',
+      11: 'question',
+      12: 'brief',
+      13: 'year',
+      14: 'month',
+      15: 'contacts',
+      16: 'tel',
+    };
+  }
+  async importDemand() {
+    const p = path.resolve(__dirname, '../../../importData/20240624', '需求库.xlsx');
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(p);
+    const sheet = wb.getWorksheet('3-技术需求库-打印');
+    if (!sheet) return;
+    const meta = this.demandMeta();
+    const specialArea1Deal = {
+      延边州: '延边朝鲜族自治州',
+    };
+    const specialArea2Deal = {
+      新区: '新区',
+      高新区: '长春高新技术产业开发区',
+      经开: '长春经济技术开发区',
+      中韩: '中韩国际合作示范区',
+      汽开: '长春汽车经济技术开发区',
+      汽开区: '长春汽车经济技术开发区',
+      // 医药高新区: '',
+      // 中新食品区: '',
+    };
+    const allData = [];
+    sheet.eachRow((row, ri) => {
+      if (ri === 1 || ri === 2 || ri === 3) {
+        // 不处理
+      } else {
+        const obj = {};
+        row.eachCell((cell, ci) => {
+          const val = cell.value;
+          const key = meta[ci];
+          if (key) obj[key] = val;
+        });
+        if (get(obj, 'company') && trim(get(obj, 'company')) !== '') allData.push(obj);
+      }
+    });
+    for (const i of allData) {
+      // #region 地区处理
+      i.area = ['吉林省'];
+      if (i.area2 === '医药高新区') {
+        i.area.push('通化市', '医药高新区');
+      } else if (i.area2 === '中新食品区') {
+        i.area.push('吉林市', '医药高新区');
+      } else {
+        const builder = this.regionModel.createQueryBuilder();
+        builder.where(`name like '%${i.area1}%'`);
+        // builder.andWhere(`name Not Like '%省%'`);
+        builder.andWhere(`level = 'city'`);
+        builder.andWhere(`code like '22%'`);
+        const r1 = await builder.getOne();
+        const r2 = await this.regionModel.findOne({ where: { name: Like(`%${i.area2}%`), code: Like('22%'), level: Equal('area') } });
+        if (r1) {
+          i.area.push(r1.name);
+          delete i.area1;
+        } else {
+          const area = specialArea1Deal[i.area1];
+          if (area) {
+            i.area.push(area);
+            delete i.area1;
+          }
+        }
+        if (r2) {
+          i.area.push(r2.name);
+          delete i.area2;
+        } else {
+          // 需要特殊处理的
+          const area = specialArea2Deal[i.area2];
+          if (area) {
+            i.area.push(area);
+          }
+          // 还有一种情况就是省市都写的一个.就不需要第二个了,所以最后一定删除
+          delete i.area2;
+        }
+      }
+      // #endregion
+    }
+    // return allData.filter(f => f.area1 || f.area2);
+    await this.demandModel.insert(allData);
+  }
+
+  projectMeta() {
+    return {
+      3: 'name',
+      4: 'brief',
+      5: 'main',
+      6: 'progress',
+      7: 'track_unit',
+      8: 'source',
+    };
+  }
+  projectIndustryMeta() {
+    return [
+      { size: 33, value: '汽车电子及新型汽车零部件' },
+      { size: 30, value: '光电子及智能传感器' },
+      { size: 24, value: '精密仪器及先进装备' },
+      { size: 60, value: '生物医药及先进医疗器械' },
+      { size: 4, value: '车规级芯片及功率半导体器件' },
+      { size: 13, value: '人工智能及智能机器人' },
+      { size: 24, value: '生物基及高性能新材料' },
+      { size: 25, value: '新能源及动力电池' },
+      { size: 10, value: '碳纤维及复合材料' },
+      { size: 5, value: '遥感卫星及航空航天' },
+      { size: 10, value: '精细化工及天然气化工' },
+      { size: 20, value: '农产品加工及绿色食品' },
+      { size: 5, value: '孵化平台' },
+      { size: 9, value: '产业技术创新平台' },
+    ];
+  }
+  async importProject() {
+    const p = path.resolve(__dirname, '../../../importData/20240624', '项目库.xlsx');
+    const wb = new Excel.Workbook();
+    await wb.xlsx.readFile(p);
+    const sheet = wb.getWorksheet('统计表');
+    if (!sheet) return;
+    const meta = this.projectMeta();
+    let allData = [];
+    const notDealRows = [1, 2, 3, 4, 5];
+    const industryMeta = this.projectIndustryMeta();
+    sheet.eachRow((row, ri) => {
+      if (notDealRows.includes(ri)) {
+        // 不处理
+      } else {
+        const obj = {};
+        row.eachCell((cell, ci) => {
+          const val = cell.value;
+          const key = meta[ci];
+          if (key) {
+            obj[key] = val;
+          }
+        });
+        const res = industryMeta.find(f => f.value === get(obj, 'name'));
+        if (!res) {
+          for (const key in obj) {
+            if (!isString(obj[key])) {
+              const rtobj = get(obj[key], 'richText');
+              let text = '';
+              if (rtobj) {
+                for (const i of rtobj) {
+                  text = `${text}${i.text}`;
+                }
+              }
+              obj[key] = text;
+            }
+          }
+          allData.push(obj);
+        }
+      }
+    });
+    // 分组,然后给加上产业字段
+    const newData = [];
+    for (const meta of industryMeta) {
+      const { size, value } = meta;
+      const nds = take(allData, size);
+      for (const i of nds) {
+        i.industry = value;
+      }
+      newData.push(...nds);
+      // 删除提取出来的数据
+      allData = differenceWith(allData, nds, isEqual);
+    }
+    await this.projectModel.insert(newData);
+    // return newData;
+  }
+}

+ 117 - 9
src/service/log/opera.service.ts

@@ -1,23 +1,23 @@
 import { Inject, MidwayWebRouterService, Provide } from '@midwayjs/core';
 import { InjectEntityModel } from '@midwayjs/typeorm';
 import { Repository } from 'typeorm';
-import { get } from 'lodash';
+import * as toqm from 'typeorm';
+import { get, pick } from 'lodash';
 import dayjs = require('dayjs');
 import { Context } from '@midwayjs/koa';
-import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
-import { Opera } from '../../entityLogs/opera.entity';
+import { Opera as operaModel } from '../../entityLogs/opera.entity';
+import { QueryOpera } from '../../frame/BaseService';
+import { Opera } from '../../frame/dbOpera';
+
 @Provide()
-export class OperaService {
+export class OperaService  {
   @Inject()
   ctx: Context;
-  @InjectEntityModel(Opera, 'logs')
-  model: Repository<Opera>;
+  @InjectEntityModel(operaModel, 'logs')
+  model: Repository<operaModel>;
   @Inject()
   webRouterService: MidwayWebRouterService;
 
-  @Inject()
-  dataSourceManager: TypeORMDataSourceManager;
-
   /**
    * 生成日志
    * 原数据和新数据格式:
@@ -62,4 +62,112 @@ export class OperaService {
       await this.model.insert(logInfo);
     }
   }
+
+
+  /**
+   * 列表查询
+   * @param query 查询条件(经过queryBuilder转换后的)
+   * @param param 有关skip和limit,order_by(数组,多字段排列)
+   */
+  async query(query: QueryOpera[], { skip = 0, limit = 0, order = {} } = {}) {
+    let findOpera: any = {};
+    // 组织查询顺序
+    let orderObject: any = {};
+    // 如果有自定义顺序,则按照自定义顺序来, 没有自定义顺序,默认按创建时间的desc查询
+    if (Object.keys(order).length > 0) {
+      for (const column in order) orderObject[column] = order[column];
+    } else orderObject = { time: 'DESC' };
+    if (query.length > 0) findOpera = this.buildFindWhere(query);
+    const builder = await this.model.createQueryBuilder().setFindOptions({ where: findOpera, skip, take: limit, order: orderObject });
+    const data = await builder.getMany();
+    const total = await builder.getCount();
+    return { data, total };
+  }
+
+  /**根据builder设置转换成options */
+  buildFindWhere(query) {
+    const result = {};
+    for (const qo of query) {
+      let val = qo.value;
+      for (const opera of qo.opera) {
+        const methods = pick(toqm, ['IsNull', 'In', 'MoreThanOrEqual', 'MoreThan', 'LessThanOrEqual', 'LessThan', 'Equal', 'Not', 'Like', 'ILike', 'Between']);
+        // const m = get(methods, Opera[opera]);
+        const m = methods[Opera[opera]];
+        // if 和 else if 都是需要特殊处理值的情况
+        // Between这个一般都是最先处理,要放到数组最前面,否则会影响value的值
+        if (Opera[opera] === Opera.Between) val = m(get(val, 0), get(val, 1));
+        else if (Opera[opera] === Opera.Like || Opera[opera] === Opera.ILike) val = m(`%${val}%`);
+        else if (Opera[opera] === Opera.LikeLeft || Opera[opera] === Opera.ILikeLeft) val = m(`%${val}`);
+        else if (Opera[opera] === Opera.LikeRight || Opera[opera] === Opera.ILikeRight) val = m(`${val}%`);
+        else if (Opera[opera] === Opera.IsNull) val = m![Opera[opera]]();
+        else val = m(val);
+      }
+      result[qo.column] = val;
+    }
+    return result;
+  }
+
+
+  /**
+   * 默认查询条件object
+   * integer: 数字 默认 全等
+   * character varying: 字符串 默认 模糊
+   * timestamp without time zone: 时间 默认不处理,手写处理方式
+   * @param {object} query 查询条件object
+   * @return 输出为查询数组
+   * [
+   *  {
+   *    column:字段,
+   *    opera:查询方式
+   *    value:具体值
+   *  }
+   * ]
+   *  e.g.:
+   * [
+   *  {
+   *    column:'nick_name',
+   *    opera:eq,
+   *    value:'admin'
+   *  }
+   * ]
+   * 形成查询数组,再由query函数处理具体查询
+   */
+  queryBuilder(query: any = {}) {
+    /**列设置,所有字段都需要设置type */
+    const columns = this.model.metadata.columns;
+    /**将array的列设置 转换为object,以便query使用*/
+    const columnsObject = {};
+    // 整理成object
+    for (const c of columns) columnsObject[c.propertyName] = c.type.toString();
+    /**返回的查询操作数组 */
+    const queryArray: QueryOpera[] = [];
+    // 根据查询条件(query),对字段进行处理
+    for (const column in query) {
+      const dataType = columnsObject[column];
+      // 没找到字段,那就直接跳过,按理说不应该找不到.但是真的找不到,也不能添加进查询条件里,会出错
+      if (!dataType) continue;
+      if (dataType === 'integer') {
+        const qo: QueryOpera = { column, value: query[column], opera: [Opera.Equal] };
+        queryArray.push(qo);
+      } else if (dataType === 'character varying') {
+        const qo: QueryOpera = { column, value: query[column], opera: [Opera.Like] };
+        queryArray.push(qo);
+      } else if (dataType === 'timestamp without time zone') {
+        //默认不处理
+      }
+    }
+
+    return queryArray;
+  }
+
+
+  /**单查询,不止用id还可以根据别的条件 */
+  async fetch(query: QueryOpera[]) {
+    const whereOptions = this.buildFindWhere(query);
+    const builder = this.model.createQueryBuilder().setFindOptions({ where: whereOptions });
+    const result = await builder.getOne();
+    return result;
+  }
+
+
 }

+ 1 - 244
src/service/util.service.ts

@@ -1,22 +1,8 @@
 import { Inject, Provide } from '@midwayjs/core';
-import * as fs from 'fs';
-import { compact, get, isArray, isObject } from 'lodash';
-import path = require('path');
-import { Repository } from 'typeorm';
 // import { Achievement } from '../entity/platform/achievement.entity';
-import { InjectEntityModel, TypeORMDataSourceManager } from '@midwayjs/typeorm';
-import { News } from '../entity/platform/news.entity';
-import { Demand } from '../entity/platform/demand.entity';
-import { Expert } from '../entity/users/expert.entity';
-import { Company } from '../entity/users/company.entity';
+import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
 import { Context } from '@midwayjs/koa';
-import * as Excel from 'exceljs';
-import { Achievement } from '../entity/platform/achievement.entity';
 import { Test } from '../entity/test.entity';
-import { ServiceError } from '../error/service.error';
-// import { upperFirst } from 'lodash';
-
-// import { User } from '../entity/system/user.entity';
 @Provide()
 export class UtilService {
   @Inject()
@@ -65,233 +51,4 @@ export class UtilService {
       // console.log(res);
     });
   }
-
-  @InjectEntityModel(Demand)
-  demandModel: Repository<Demand>;
-  @InjectEntityModel(Achievement)
-  achievementModel: Repository<Achievement>;
-  @InjectEntityModel(Expert)
-  expertModel: Repository<Expert>;
-  async initData() {
-    console.log('in initData');
-    await this.importRequirementFromExcel();
-    // await this.importAchieveFromExcel();
-    // await this.importExpertFromExcel();
-  }
-  async importRequirementFromExcel() {
-    const path = 'C:/document/需求库.xlsx';
-    const wb = new Excel.Workbook();
-    await wb.xlsx.readFile(path);
-    const sheet = wb.getWorksheet(1);
-    const meta = this.requirementMeta();
-    const allData = [];
-    const cityArr = ['长春', '吉林', '通化', '白山', '辽源', '四平', '白城', '松原', '延边州', '延边'];
-    const areaArr = [
-      '五棵树经济开发区',
-      '南关区',
-      '宽城区',
-      '朝阳区',
-      '二道区',
-      '绿园区',
-      '双阳区',
-      '九台区',
-      '公主岭市',
-      '榆树市',
-      '德惠市',
-      '农安县',
-      '昌邑区',
-      '龙潭区',
-      '船营区',
-      '丰满区',
-      '蛟河市',
-      '桦甸市',
-      '舒兰市',
-      '磐石市',
-      '永吉县',
-      '东昌区',
-      '二道江区',
-      '集安市',
-      '梅河口市',
-      '通化县',
-      '辉南县',
-      '柳河县',
-      '浑江区',
-      '江源区',
-      '临江市',
-      '抚松县',
-      '靖宇县',
-      '长白朝鲜族自治县',
-      '龙山区',
-      '西安区',
-      '东丰县',
-      '东辽县',
-      '铁西区',
-      '铁东区',
-      '双辽市',
-      '梨树县',
-      '伊通满族自治县',
-      '洮北区',
-      '洮南市',
-      '大安市',
-      '镇赉县',
-      '通榆县',
-      '宁江区',
-      '扶余市',
-      '长岭县',
-      '乾安县',
-      '前郭尔罗斯蒙古族自治县',
-      '延吉市',
-      '图们市',
-      '敦化市',
-      '珲春市',
-      '龙井市',
-      '和龙市',
-      '汪清县',
-      '安图县',
-    ];
-    const specialList = [
-      { e: '高新区', to: '高新技术产业开发区' },
-      { e: '高新', to: '高新技术产业开发区' },
-      { e: '经开', to: '经济技术开发区' },
-      { e: '五棵树', to: '五棵树经济开发区' },
-      { e: '北湖', to: '北湖科技开发区' },
-      { e: '净月', to: '净月高新技术产业开发区' },
-      { e: '绿园经济', to: '绿园经济开发区' },
-    ];
-    const ignoreArea = ['吉林', '长春', '白城'];
-    const specialAreaList = [
-      { e: '梅河口', to: ['吉林省', '通化市', '梅河口市'] },
-      { e: '德惠', to: ['吉林省', '长春市', '德惠市'] },
-      { e: '敦化', to: ['吉林省', '延边州', '敦化市'] },
-      { e: '延吉', to: ['吉林省', '延边州', '延吉市'] },
-      { e: '柳河', to: ['吉林省', '通化市', '柳河县'] },
-    ];
-    sheet.eachRow((row, ri) => {
-      if (ri === 1 || ri === 2) {
-        // 不处理
-      } else {
-        const obj = {};
-        row.eachCell((cell, ci) => {
-          const val = cell.value as string;
-          const key = meta[ci];
-          if (ci === 3) {
-            let area = ['吉林省'];
-            // 处理地区
-            const res = cityArr.find(f => val.includes(f));
-            if (res) {
-              // 有市级关键词的, 延边州不需要处理
-              if (res === '延边') area.push('延边州');
-              else if (res !== '延边州') area.push(`${res}市`);
-              else area.push(res);
-              const elseStr = val.replace(res, '');
-              if (elseStr !== '' && !ignoreArea.includes(elseStr)) {
-                const areaVal = areaArr.find(f => f.includes(elseStr));
-                if (areaVal) area.push(areaVal);
-                else {
-                  const rs = specialList.find(f => elseStr.includes(f.e));
-                  if (rs) area.push(rs.to);
-                }
-              }
-            } else {
-              const res = specialAreaList.find(f => val.includes(f.e));
-              if (res) area = res.to;
-              else obj['no_area'] = true;
-            }
-            obj[key] = area;
-          } else if (ci === 6) {
-            // 分离人员和电话
-            const strReg = /([\u4e00-\u9fa5]{3}|[\u4e00-\u9fa5]{2})/g;
-            const strRes = val.match(strReg);
-            const numRes = val.replace(strReg, '').replace('\n', '');
-            if (isArray(strRes)) obj['contacts'] = strRes.join(';');
-            if (isArray(numRes)) obj['tel'] = numRes.join(';');
-            if (numRes) obj['tel'] = numRes;
-          } else if (key) obj[key] = val;
-        });
-        allData.push(obj);
-      }
-    });
-    const res = await this.demandModel.insert(allData);
-    return res;
-  }
-
-  requirementMeta() {
-    return {
-      2: 'field',
-      3: 'area',
-      4: 'company',
-      5: 'brief',
-      6: 'contacts',
-      7: 'year',
-    };
-  }
-
-  async importAchieveFromExcel() {
-    const path = 'C:/document/成果库.xlsx';
-    const wb = new Excel.Workbook();
-    await wb.xlsx.readFile(path);
-    const sheet = wb.getWorksheet(1);
-    const meta = this.achieveMeta();
-    const allData = [];
-    sheet.eachRow((row, ri) => {
-      if (ri === 1 || ri === 2) {
-        // 不处理
-      } else {
-        const obj = {};
-        row.eachCell((cell, ci) => {
-          const val = cell.value;
-          const key = meta[ci];
-          if (key) obj[key] = val;
-        });
-        allData.push(obj);
-      }
-    });
-    return await this.achievementModel.insert(allData);
-  }
-  achieveMeta() {
-    return {
-      2: 'field',
-      3: 'name',
-      4: 'brief',
-      5: 'source',
-      6: 'person',
-      7: 'tel',
-    };
-  }
-
-  async importExpertFromExcel() {
-    const path = 'C:/document/专家库.xlsx';
-    const wb = new Excel.Workbook();
-    await wb.xlsx.readFile(path);
-    const sheet = wb.getWorksheet(1);
-    const rows = sheet.getRows(3, 200);
-    const meta = this.exportsMeta();
-    const allData = [];
-    for (const row of rows) {
-      const obj = {};
-      row.eachCell((cell, index) => {
-        let val = cell.value as string;
-        if (index === 4) {
-          const varr = val.split('').filter(f => f !== ' ');
-          val = varr.join('');
-        }
-        const key = meta[index];
-        obj[key] = val;
-      });
-      allData.push(obj);
-    }
-    const res = await this.expertModel.insert(allData);
-    return res;
-  }
-
-  exportsMeta() {
-    return {
-      1: 'industry_type',
-      2: 'industry',
-      3: 'work_type',
-      4: 'name',
-      5: 'work',
-      6: 'title',
-    };
-  }
 }