diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index df6d9f84..00000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2020 Huawei Technologies Co.,Ltd.
- *
- * InulaJS is licensed under Mulan PSL v2.
- * You can use this software according to the terms and conditions of the Mulan PSL v2.
- * You may obtain a copy of Mulan PSL v2 at:
- *
- * http://license.coscl.org.cn/MulanPSL2
- *
- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
- * See the Mulan PSL v2 for more details.
- */
-
-module.exports = {
- extends: [
- 'eslint:recommended',
- 'plugin:@typescript-eslint/eslint-recommended',
- 'plugin:@typescript-eslint/recommended',
- 'prettier',
- ],
- root: true,
-
- plugins: ['jest', 'no-for-of-loops', 'no-function-declare-after-return', 'react', '@typescript-eslint'],
-
- parser: '@typescript-eslint/parser',
- parserOptions: {
- ecmaVersion: 8,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true,
- modules: true,
- experimentalObjectRestSpread: true,
- },
- },
- env: {
- browser: true,
- jest: true,
- node: true,
- es6: true,
- },
- rules: {
- '@typescript-eslint/no-explicit-any': 'off',
- '@typescript-eslint/explicit-module-boundary-types': 'off',
- '@typescript-eslint/no-non-null-assertion': 'off',
- '@typescript-eslint/no-empty-function': 'off',
- semi: ['warn', 'always'],
- quotes: ['warn', 'single'],
- 'accessor-pairs': 'off',
- 'brace-style': ['error', '1tbs'],
- 'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
- 'max-lines-per-function': 'off',
- 'object-curly-newline': 'off',
- // 尾随逗号
- 'comma-dangle': ['error', 'only-multiline'],
-
- 'no-constant-condition': 'off',
- 'no-for-of-loops/no-for-of-loops': 'error',
- 'no-function-declare-after-return/no-function-declare-after-return': 'error',
- },
- globals: {
- isDev: true,
- isTest: true,
- },
- overrides: [
- {
- files: ['scripts/__tests__/**/*.js'],
- globals: {
- container: true,
- },
- },
- ],
-};
diff --git a/.gitignore b/.gitignore
index 7fa547da..6a0e585e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,5 @@
-node_modules
-build/
+/node_modules
.idea
.vscode
package-lock.json
-libs/**/dist
-scripts/*.ejs
+pnpm-lock.yaml
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 8b137891..00000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/app_define.json b/app_define.json
deleted file mode 100644
index a674d06c..00000000
--- a/app_define.json
+++ /dev/null
@@ -1 +0,0 @@
-{"fileVersion":"1","name":"Inula","serviceId":"067e5bef6cd240ae9460229d107a99a6","description":"","version":"1.0.0","type":"microService","processes":{"Inula":{"subscribes":[]}}}
diff --git a/libs/inula/README.md b/libs/inula/README.md
deleted file mode 100644
index 95818b1f..00000000
--- a/libs/inula/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# `inula`
diff --git a/libs/inula/package.json b/libs/inula/package.json
deleted file mode 100644
index 0e57bbe8..00000000
--- a/libs/inula/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "inulajs",
- "description": "InulaJS is a JavaScript framework library.",
- "keywords": [
- "inula"
- ],
- "version": "0.0.52",
- "homepage": "",
- "bugs": "",
- "main": "index.js",
- "repository": {},
- "engines": {
- "node": ">=0.10.0"
- },
- "dependencies": {},
- "types": "@types/index.d.ts"
-}
diff --git a/package.json b/package.json
index d2c20795..b32ee29c 100644
--- a/package.json
+++ b/package.json
@@ -3,19 +3,9 @@
"description": "InulaJS is a JavaScript framework library.",
"version": "0.0.52",
"private": true,
- "workspaces": [
- "libs/*"
- ],
"scripts": {
"lint": "eslint . --ext .ts --fix",
- "prettier": "prettier -w libs/**/*.ts",
- "build": "rollup --config ./scripts/rollup/rollup.config.js",
- "build:watch": "rollup --watch --config ./scripts/rollup/rollup.config.js",
- "build:inula3rdLib-dev": "npm run build & node ./scripts/gen3rdLib.js build:inula3rdLib-dev",
- "build-types": "tsc -p libs/inula/index.ts --emitDeclarationOnly --declaration --declarationDir ./build/inula/@types --skipLibCheck || echo \\\"WARNING: TSC exited with status $?\\\"",
- "debug-test": "yarn test --debug",
- "test": "jest --config=jest.config.js",
- "watch-test": "yarn test --watch --dev"
+ "prettier": "prettier -w libs/**/*.ts"
},
"devDependencies": {
"@babel/core": "7.16.7",
@@ -69,6 +59,5 @@
"engines": {
"node": ">=10.x",
"npm": ">=7.x"
- },
- "dependencies": {}
+ }
}
diff --git a/.editorconfig b/packages/create-inula/.editorconfig
similarity index 100%
rename from .editorconfig
rename to packages/create-inula/.editorconfig
diff --git a/packages/create-inula/.gitignore b/packages/create-inula/.gitignore
new file mode 100644
index 00000000..30ca8b5e
--- /dev/null
+++ b/packages/create-inula/.gitignore
@@ -0,0 +1,5 @@
+/node_modules
+.idea
+.vscode
+package-lock.json
+/build
diff --git a/packages/create-inula/bin/cli.js b/packages/create-inula/bin/cli.js
new file mode 100644
index 00000000..5933b66e
--- /dev/null
+++ b/packages/create-inula/bin/cli.js
@@ -0,0 +1,3 @@
+#! /usr/bin/env node
+
+require('../index.js');
diff --git a/packages/create-inula/index.js b/packages/create-inula/index.js
new file mode 100644
index 00000000..1e0c565f
--- /dev/null
+++ b/packages/create-inula/index.js
@@ -0,0 +1,21 @@
+#! /usr/bin/env node
+
+const yParser = require('yargs-parser');
+const run = require('./lib/run');
+
+// args 为文件名后所有输入
+const args = yParser(process.argv.slice(2));
+
+const name = args._[0] || '';
+
+const { type } = args;
+delete args.type;
+
+(async () => {
+ await run({
+ name,
+ type,
+ args,
+ });
+ process.exit(0);
+})();
diff --git a/packages/create-inula/lib/BasicGenerator.js b/packages/create-inula/lib/BasicGenerator.js
new file mode 100644
index 00000000..ec38bd0a
--- /dev/null
+++ b/packages/create-inula/lib/BasicGenerator.js
@@ -0,0 +1,154 @@
+const fs = require('fs');
+const path = require('path');
+const Generator = require('yeoman-generator');
+const { globSync } = require('glob');
+const { statSync } = require('fs');
+const { basename } = require('path');
+const _ = require('lodash');
+_.extend(Generator.prototype, require('yeoman-generator/lib/actions/install'));
+
+function noop() {
+ return true;
+}
+
+class BasicGenerator extends Generator {
+ constructor(opts) {
+ super(opts);
+ this.opts = opts;
+ this.name = basename(opts.env.cwd);
+ }
+
+ isTsFile(f) {
+ return f.endsWith('.ts') || f.endsWith('.tsx') || !!/(tsconfig\.json)/g.test(f);
+ }
+
+ /**
+ * 拷贝文件
+ * @param {string} src 源文件路径
+ * @param {string} dest 目标文件路径
+ * @param {function} filter 过滤函数
+ */
+ copyFile(src, dest, filter = () => true) {
+ if (src.indexOf('package.json') !== -1 && fs.existsSync(dest)) {
+ this.mergePackage(filePath, destFilePath);
+ return;
+ }
+ const readStream = fs.createReadStream(src);
+ const writeStream = fs.createWriteStream(dest);
+ readStream.pipe(writeStream);
+ readStream.on('error', err => console.error(err));
+ writeStream.on('error', err => console.error(err));
+ // writeStream.on('finish', () => console.log(`Copied ${src} to ${dest}`));
+ }
+
+ /**
+ * 拷贝文件夹
+ * @param {string} src 源文件夹路径
+ * @param {string} dest 目标文件夹路径
+ * @param {function} filter 过滤函数
+ */
+ copyFolder(src, dest, filter = () => true) {
+ if (!fs.existsSync(dest)) {
+ fs.mkdirSync(dest, { recursive: true });
+ }
+ const files = fs.readdirSync(src);
+ for (const file of files) {
+ const srcPath = path.join(src, file);
+ const destPath = path.join(dest, file);
+ const stats = fs.statSync(srcPath);
+ if (stats.isFile() && filter(srcPath)) {
+ this.copyFile(srcPath, destPath);
+ } else if (stats.isDirectory()) {
+ this.copyFolder(srcPath, destPath, filter);
+ }
+ }
+ }
+
+ writeFiles(src, dest, { context, filterFiles = noop }) {
+ const files = globSync('**/*', {
+ cwd: src,
+ dot: true,
+ })
+ .filter(filterFiles)
+ .forEach(file => {
+ const filePath = path.join(src, file);
+ if (statSync(filePath).isFile()) {
+ this.fs.copyTpl(filePath, path.join(dest, file), context);
+ }
+ });
+ }
+
+ copyFiles({ src, dest, context, filterFiles = noop }) {
+ const files = globSync('**/*', {
+ cwd: src,
+ dot: true,
+ })
+ .filter(filterFiles)
+ .forEach(file => {
+ const filePath = path.resolve(src, file);
+ const destFilePath = path.resolve(dest, file);
+ if (statSync(filePath).isFile()) {
+ if (file === 'package.json' && fs.existsSync(destFilePath)) {
+ this.mergePackage(filePath, destFilePath);
+ } else {
+ this.fs.copyTpl(filePath, path.resolve(dest, file.replace(/^_/, '.')), context);
+ }
+ }
+ });
+ }
+
+ mergePackage(src, dest) {
+ if (fs.existsSync(dest)) {
+ const existing = JSON.parse(fs.readFileSync(dest, 'utf8'));
+ const newPackage = JSON.parse(fs.readFileSync(src, 'utf8'));
+ const pkg = Object.assign({}, existing, newPackage);
+ fs.writeFileSync(dest, JSON.stringify(pkg, null, 2) + '\n');
+ }
+ }
+
+ traverseDirCapture(dir, dirCallback, fileCallback) {
+ for (const filename of fs.readdirSync(dir)) {
+ const fullpath = path.resolve(dir, filename);
+ if (fs.lstatSync(fullpath).isDirectory()) {
+ dirCallback(fullpath);
+ if (fs.existsSync(fullpath)) {
+ this.traverseDirCapture(fullpath, dirCallback, fileCallback);
+ }
+ continue;
+ }
+ fileCallback(fullpath);
+ }
+ }
+
+ traverseDirBubble(dir, dirCallback, fileCallback) {
+ for (const filename of fs.readdirSync(dir)) {
+ const fullpath = path.resolve(dir, filename);
+ if (fs.lstatSync(fullpath).isDirectory()) {
+ this.traverseDirBubble(fullpath, dirCallback, fileCallback);
+ dirCallback(fullpath);
+ continue;
+ }
+ fileCallback(fullpath);
+ }
+ }
+
+ emptyDir(dir) {
+ if (!fs.existsSync(dir)) {
+ return;
+ }
+
+ this.traverseDirBubble(
+ dir,
+ dir => fs.rmdirSync(dir),
+ file => fs.unlinkSync(file)
+ );
+ }
+
+ prompt(questions) {
+ process.send && process.send({ type: 'prompt' });
+ process.emit('message', { type: 'prompt' });
+ return super.prompt(questions);
+ }
+}
+
+module.exports = BasicGenerator;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/index.js b/packages/create-inula/lib/generators/InulaJS-antd/index.js
new file mode 100644
index 00000000..d37dabab
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/index.js
@@ -0,0 +1,30 @@
+const debug = require('debug')('create-umi:generator');
+const BasicGenerator = require('../../BasicGenerator');
+const fs = require('fs');
+
+class Generator extends BasicGenerator {
+ prompting() {
+ return this.prompt([
+ {
+ type: 'list',
+ name: 'bundlerType',
+ message: 'Please select the build type',
+ choices: ['webpack', 'vite'],
+ },
+ ]).then(props => {
+ this.prompts = props;
+ console.log('finish prompting');
+ });
+ }
+ writing() {
+ const src = this.templatePath(this.prompts.bundlerType);
+ const dest = this.destinationPath();
+ this.writeFiles(src, dest, {
+ context: {
+ ...this.prompts,
+ },
+ });
+ }
+}
+
+module.exports = Generator;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/meta.json b/packages/create-inula/lib/generators/InulaJS-antd/meta.json
new file mode 100644
index 00000000..40f5e08d
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/meta.json
@@ -0,0 +1,3 @@
+{
+ "description": "inula-antd template."
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/.gitignore b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/index.html b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/index.html
new file mode 100644
index 00000000..1453e8e6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ Vite + React
+
+
+
+
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/_utils.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/_utils.js
new file mode 100644
index 00000000..1a1e2358
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/_utils.js
@@ -0,0 +1,58 @@
+/**
+ * Query objects that specify keys and values in an array where all values are objects.
+ * @param {array} array An array where all values are objects, like [{key:1},{key:2}].
+ * @param {string} key The key of the object that needs to be queried.
+ * @param {string} value The value of the object that needs to be queried.
+ * @return {object|undefined} Return frist object when query success.
+ */
+export function queryArray(array, key, value) {
+ if (!Array.isArray(array)) {
+ return;
+ }
+ return array.filter(_ => _[key] === value);
+}
+
+export function randomNumber(min, max) {
+ return Math.floor(Math.random() * (max - min) + min);
+}
+
+export function randomAvatar() {
+ const avatarList = [
+ 'photo-1549492864-2ec7d66ffb04.jpeg',
+ 'photo-1480535339474-e083439a320d.jpeg',
+ 'photo-1523419409543-a5e549c1faa8.jpeg',
+ 'photo-1519648023493-d82b5f8d7b8a.jpeg',
+ 'photo-1523307730650-594bc63f9d67.jpeg',
+ 'photo-1522962506050-a2f0267e4895.jpeg',
+ 'photo-1489779162738-f81aed9b0a25.jpeg',
+ 'photo-1534308143481-c55f00be8bd7.jpeg',
+ 'photo-1519336555923-59661f41bb45.jpeg',
+ 'photo-1551438632-e8c7d9a5d1b7.jpeg',
+ 'photo-1525879000488-bff3b1c387cf.jpeg',
+ 'photo-1487412720507-e7ab37603c6f.jpeg',
+ 'photo-1510227272981-87123e259b17.jpeg',
+ ];
+ return `//image.zuiidea.com/${
+ avatarList[randomNumber(0, avatarList.length - 1)]
+ }?imageView2/1/w/200/h/200/format/webp/q/75|imageslim`;
+}
+
+export const Constant = {
+ ApiPrefix: '/api/v1',
+ NotFound: {
+ message: 'Not Found',
+ documentation_url: '',
+ },
+ Color: {
+ green: '#64ea91',
+ blue: '#8fc9fb',
+ purple: '#d897eb',
+ red: '#f69899',
+ yellow: '#f8c82e',
+ peach: '#f797d6',
+ borderBase: '#e5e5e5',
+ borderSplit: '#f4f4f4',
+ grass: '#d6fbb5',
+ sky: '#c1e0fc',
+ },
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/dashboard.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/dashboard.js
new file mode 100644
index 00000000..36135aea
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/dashboard.js
@@ -0,0 +1,142 @@
+import { Constant } from './_utils';
+import Mock from 'mockjs';
+
+const { ApiPrefix, Color } = Constant;
+
+const Dashboard = Mock.mock({
+ 'sales|8': [
+ {
+ 'name|+1': 2008,
+ 'Clothes|200-500': 1,
+ 'Food|180-400': 1,
+ 'Electronics|300-550': 1,
+ },
+ ],
+ cpu: {
+ 'usage|50-600': 1,
+ space: 825,
+ 'cpu|40-90': 1,
+ 'data|20': [
+ {
+ 'cpu|20-80': 1,
+ },
+ ],
+ },
+ browser: [
+ {
+ name: 'Google Chrome',
+ percent: 43.3,
+ status: 1,
+ },
+ {
+ name: 'Mozilla Firefox',
+ percent: 33.4,
+ status: 2,
+ },
+ {
+ name: 'Apple Safari',
+ percent: 34.6,
+ status: 3,
+ },
+ {
+ name: 'Internet Explorer',
+ percent: 12.3,
+ status: 4,
+ },
+ {
+ name: 'Opera Mini',
+ percent: 3.3,
+ status: 1,
+ },
+ {
+ name: 'Chromium',
+ percent: 2.53,
+ status: 1,
+ },
+ ],
+ user: {
+ name: 'github',
+ sales: 3241,
+ sold: 3556,
+ },
+ 'completed|12': [
+ {
+ 'name|+1': 2008,
+ 'Task complete|200-1000': 1,
+ 'Cards Complete|200-1000': 1,
+ },
+ ],
+ 'comments|5': [
+ {
+ name: '@last',
+ 'status|1-3': 1,
+ content: '@sentence',
+ avatar() {
+ return Mock.Random.image('48x48', Mock.Random.color(), '#757575', 'png', this.name.substr(0, 1));
+ },
+ date() {
+ return `2016-${Mock.Random.date('MM-dd')} ${Mock.Random.time('HH:mm:ss')}`;
+ },
+ },
+ ],
+ 'recentSales|36': [
+ {
+ 'id|+1': 1,
+ name: '@last',
+ 'status|1-4': 1,
+ date() {
+ return `${Mock.Random.integer(2015, 2016)}-${Mock.Random.date('MM-dd')} ${Mock.Random.time('HH:mm:ss')}`;
+ },
+ 'price|10-200.1-2': 1,
+ },
+ ],
+ quote: {
+ name: 'Joho Doe',
+ title: 'Graphic Designer',
+ content:
+ "I'm selfish, impatient and a little insecure. I make mistakes, I am out of control and at times hard to handle. But if you can't handle me at my worst, then you sure as hell don't deserve me at my best.",
+ avatar: '//cdn.antd-admin.zuiidea.com/bc442cf0cc6f7940dcc567e465048d1a8d634493198c4-sPx5BR_fw236',
+ },
+ numbers: [
+ {
+ icon: 'pay-circle-o',
+ color: Color.green,
+ title: 'Online Review',
+ number: 2781,
+ },
+ {
+ icon: 'team',
+ color: Color.blue,
+ title: 'New Customers',
+ number: 3241,
+ },
+ {
+ icon: 'message',
+ color: Color.purple,
+ title: 'Active Projects',
+ number: 253,
+ },
+ {
+ icon: 'shopping-cart',
+ color: Color.red,
+ title: 'Referrals',
+ number: 4324,
+ },
+ ],
+});
+
+// module.exports = {
+// [`get ${ApiPrefix}/dashboard`](req, res) {
+// res.json(Dashboard);
+// },
+// };
+
+export default [
+ {
+ url: `${ApiPrefix}/dashboard`,
+ method: 'get',
+ response: () => {
+ return Dashboard;
+ },
+ },
+];
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/route.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/route.js
new file mode 100644
index 00000000..fc19d968
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/route.js
@@ -0,0 +1,41 @@
+import { Constant } from './_utils';
+
+const { ApiPrefix } = Constant;
+
+const database = [
+ {
+ id: '1',
+ icon: 'dashboard',
+ name: 'Dashboard',
+ zh: {
+ name: '仪表盘',
+ },
+ 'pt-br': {
+ name: 'Dashboard',
+ },
+ route: '/dashboard',
+ },
+ {
+ id: '2',
+ breadcrumbParentId: '',
+ name: 'User Management',
+ zh: {
+ name: '用户管理',
+ },
+ 'pt-br': {
+ name: 'Usuário',
+ },
+ icon: 'user',
+ route: '/user',
+ },
+];
+
+export default [
+ {
+ url: `${ApiPrefix}/routes`,
+ method: 'get',
+ response: () => {
+ return database;
+ },
+ },
+];
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/user.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/user.js
new file mode 100644
index 00000000..18dd168e
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/mock/user.js
@@ -0,0 +1,155 @@
+import { Constant } from './_utils';
+import Mock from 'mockjs';
+import qs from 'qs';
+import { randomAvatar } from './_utils';
+import url from 'url';
+
+const { ApiPrefix } = Constant;
+
+let usersListData = Mock.mock({
+ 'data|80-100': [
+ {
+ id: '@id',
+ name: '@name',
+ nickName: '@last',
+ phone: /^1[34578]\d{9}$/,
+ 'age|11-99': 1,
+ address: '@county(true)',
+ isMale: '@boolean',
+ email: '@email',
+ createTime: '@datetime',
+ avatar() {
+ return randomAvatar();
+ },
+ },
+ ],
+});
+
+let database = usersListData.data;
+
+const EnumRoleType = {
+ ADMIN: 'admin',
+ DEFAULT: 'guest',
+ DEVELOPER: 'developer',
+};
+
+const userPermission = {
+ DEFAULT: {
+ visit: ['1', '2', '21', '7', '5', '51', '52', '53'],
+ role: EnumRoleType.DEFAULT,
+ },
+ ADMIN: {
+ role: EnumRoleType.ADMIN,
+ },
+ DEVELOPER: {
+ role: EnumRoleType.DEVELOPER,
+ },
+};
+
+const adminUsers = [
+ {
+ id: 0,
+ username: 'admin',
+ password: 'admin',
+ permissions: userPermission.ADMIN,
+ avatar: randomAvatar(),
+ },
+ {
+ id: 1,
+ username: 'guest',
+ password: 'guest',
+ permissions: userPermission.DEFAULT,
+ avatar: randomAvatar(),
+ },
+ {
+ id: 2,
+ username: '吴彦祖',
+ password: '123456',
+ permissions: userPermission.DEVELOPER,
+ avatar: randomAvatar(),
+ },
+];
+
+const queryArray = (array, key, keyAlias = 'key') => {
+ if (!(array instanceof Array)) {
+ return null;
+ }
+ let data;
+
+ for (let item of array) {
+ if (item[keyAlias] === key) {
+ data = item;
+ break;
+ }
+ }
+
+ if (data) {
+ return data;
+ }
+ return null;
+};
+
+const NOTFOUND = {
+ message: 'Not Found',
+ documentation_url: 'http://localhost:8000/request',
+};
+
+export default [
+ {
+ url: `${ApiPrefix}/user`,
+ method: 'get',
+ response: () => {
+ return {
+ success: true,
+ user: adminUsers[0],
+ };
+ },
+ },
+ {
+ url: `${ApiPrefix}/users`,
+ method: 'get',
+ response: req => {
+ const { query } = url.parse(req.url, true);
+ let { pageSize, page, ...other } = query;
+ pageSize = pageSize || 10;
+ page = page || 1;
+
+ let newData = database;
+ for (let key in other) {
+ if ({}.hasOwnProperty.call(other, key)) {
+ newData = newData.filter(item => {
+ if ({}.hasOwnProperty.call(item, key)) {
+ if (key === 'address') {
+ return other[key].every(iitem => item[key].indexOf(iitem) > -1);
+ } else if (key === 'createTime') {
+ const start = new Date(other[key][0]).getTime();
+ const end = new Date(other[key][1]).getTime();
+ const now = new Date(item[key]).getTime();
+
+ if (start && end) {
+ return now >= start && now <= end;
+ }
+ return true;
+ }
+ return String(item[key]).trim().indexOf(decodeURI(other[key]).trim()) > -1;
+ }
+ return true;
+ });
+ }
+ }
+ return {
+ data: newData.slice((page - 1) * pageSize, page * pageSize),
+ total: newData.length,
+ };
+ },
+ },
+ {
+ url: `${ApiPrefix}/users/delete`,
+ method: 'post',
+ response: req => {
+ const { ids = [] } = req.body;
+ database = database.filter(item => !ids.some(_ => _ === item.id));
+ },
+ },
+ {},
+];
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/package.json b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/package.json
new file mode 100644
index 00000000..4bc6e5fe
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/package.json
@@ -0,0 +1,80 @@
+{
+ "name": "my-react-app",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@ant-design/icons": "^5.0.1",
+ "@babel/plugin-proposal-export-default-from": "^7.18.6",
+ "@babel/plugin-transform-react-jsx": "^7.21.0",
+ "@babel/runtime": "7.6.2",
+ "inula": "0.0.52",
+ "antd": "^4.0.0",
+ "axios": "^0.21.0",
+ "classnames": "^2.2.6",
+ "echarts": "^5.0.0",
+ "history": "^5.3.0",
+ "lodash": "^4.17.11",
+ "moment": "2.24.0",
+ "nprogress": "^0.2.0",
+ "path-to-regexp": "^6.1.0",
+ "prop-types": "^15.7.0",
+ "qs": "^6.10.0",
+ "react-countup": "^4.2.0",
+ "react-dom": "17.0.2",
+ "react-draft-wysiwyg": "^1.13.0",
+ "react-helmet": "^6.0.0",
+ "react-intl": "^6.3.2",
+ "react-perfect-scrollbar": "^1.5.0",
+ "react-router": "^6.10.0",
+ "react-router-dom": "^6.10.0",
+ "recharts": "^2.0.0",
+ "store": "^2.0.0"
+ },
+ "devDependencies": {
+ "@babel/cli": "7.18.6",
+ "@babel/core": "^7.18.6",
+ "@babel/eslint-parser": "7.18.2",
+ "@babel/plugin-proposal-class-properties": "7.18.6",
+ "@babel/plugin-syntax-dynamic-import": "7.8.3",
+ "@babel/plugin-syntax-jsx": "^7.18.6",
+ "@babel/plugin-transform-flow-strip-types": "^7.18.6",
+ "@babel/plugin-transform-runtime": "^7.18.6",
+ "@babel/preset-env": "^7.18.6",
+ "@babel/preset-react": "^7.18.6",
+ "@babel/preset-typescript": "^7.18.6",
+ "@babel/runtime": "7.18.6",
+ "@babel/types": "7.18.6",
+ "@types/react": "^18.0.27",
+ "@types/react-dom": "^18.0.10",
+ "@vitejs/plugin-react": "^3.1.0",
+ "@vitejs/plugin-react-refresh": "^1.3.5",
+ "babel-loader": "8.2.5",
+ "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+ "cross-env": "7.0.3",
+ "css-loader": "^4.3.0",
+ "eslint": "^7.0.0",
+ "express-interceptor": "1.2.0",
+ "file-loader": "^6.2.0",
+ "html-webpack-plugin": "^5.5.0",
+ "less": "^4.1.3",
+ "less-vars-to-js": "^1.3.0",
+ "mockjs": "^1.1.0",
+ "prettier": "^2.0.0",
+ "react-router": "5.2.0",
+ "react-router-dom": "5.0.1",
+ "style-loader": "^3.2.2",
+ "ts-loader": "^9.3.1",
+ "tsconfig-paths-webpack-plugin": "^4.0.1",
+ "typescript": "^4.2.3",
+ "url-loader": "^4.1.1",
+ "vite": "^4.2.1",
+ "vite-plugin-mock": "^2.9.6",
+ "vite-plugin-require-transform": "^1.0.12"
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/america.svg b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/america.svg
new file mode 100644
index 00000000..8cab835c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/america.svg
@@ -0,0 +1,63 @@
+
+
+
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/china.svg b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/china.svg
new file mode 100644
index 00000000..4e3dbbfe
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/china.svg
@@ -0,0 +1,23 @@
+
+
+
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/favicon.ico b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/favicon.ico
new file mode 100644
index 00000000..7ca2170e
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/favicon.ico differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo.svg b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo.svg
new file mode 100644
index 00000000..ce7afe5c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@128.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@128.png
new file mode 100644
index 00000000..5e218d8c
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@128.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@144.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@144.png
new file mode 100644
index 00000000..347e0dfe
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@144.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@152.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@152.png
new file mode 100644
index 00000000..900dc3c7
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@152.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@192.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@192.png
new file mode 100644
index 00000000..342ab1e9
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@192.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@384.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@384.png
new file mode 100644
index 00000000..c487f36b
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@384.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@512.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@512.png
new file mode 100644
index 00000000..c2b44dc8
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@512.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@72.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@72.png
new file mode 100644
index 00000000..126e5efe
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@72.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@96.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@96.png
new file mode 100644
index 00000000..de9a9fba
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/logo/logo@96.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/portugal.svg b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/portugal.svg
new file mode 100644
index 00000000..a535e696
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/portugal.svg
@@ -0,0 +1,40 @@
+
+
+
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/vite.svg b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/vite.svg
new file mode 100644
index 00000000..e7b8dfb1
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/assets/react.svg b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/assets/react.svg
new file mode 100644
index 00000000..6c87de9b
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/DropOption/DropOption.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/DropOption/DropOption.js
new file mode 100644
index 00000000..454409f3
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/DropOption/DropOption.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { BarsOutlined, DownOutlined } from '@ant-design/icons';
+import { Dropdown, Button, Menu } from 'antd';
+
+const DropOption = ({ onMenuClick, menuOptions = [], buttonStyle, dropdownProps }) => {
+ const menu = menuOptions.map(item => {item.name});
+ return (
+ {menu}} {...dropdownProps}>
+
+
+ );
+};
+
+DropOption.propTypes = {
+ onMenuClick: PropTypes.func,
+ menuOptions: PropTypes.array.isRequired,
+ buttonStyle: PropTypes.object,
+ dropdownProps: PropTypes.object,
+};
+
+export default DropOption;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/DropOption/package.json b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/DropOption/package.json
new file mode 100644
index 00000000..a15afe7a
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/DropOption/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "DropOption",
+ "version": "0.0.0",
+ "private": true,
+ "main": "DropOption.js"
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/Editor.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/Editor.js
new file mode 100644
index 00000000..9b500b18
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/Editor.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Editor } from 'react-draft-wysiwyg';
+import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
+import styles from './Editor.module.less';
+
+const DraftEditor = props => {
+ return (
+
+ );
+};
+
+export default DraftEditor;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/Editor.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/Editor.module.less
new file mode 100644
index 00000000..2cea380a
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/Editor.module.less
@@ -0,0 +1,106 @@
+.wrapper {
+ height: 500px;
+
+ :global {
+ .rdw-dropdownoption-default {
+ padding: 6px;
+ }
+
+ .rdw-dropdown-optionwrapper {
+ box-sizing: content-box;
+ width: 100%;
+ border-radius: 0 0 2px 2px;
+ &:hover {
+ box-shadow: none;
+ }
+ }
+
+ .rdw-inline-wrapper {
+ flex-wrap: wrap;
+ margin-bottom: 0;
+
+ .rdw-option-wrapper {
+ margin-bottom: 6px;
+ }
+ }
+
+ .rdw-option-active {
+ box-shadow: 1px 1px 0 #e8e8e8 inset;
+ }
+
+ .rdw-colorpicker-option {
+ box-shadow: none;
+ }
+
+ .rdw-colorpicker-modal,
+ .rdw-embedded-modal,
+ .rdw-emoji-modal,
+ .rdw-image-modal,
+ .rdw-link-modal {
+ box-shadow: 4px 4px 40px rgba(0, 0, 0, 0.05);
+ }
+
+ .rdw-colorpicker-modal,
+ .rdw-embedded-modal,
+ .rdw-link-modal {
+ height: auto;
+ }
+
+ .rdw-emoji-modal {
+ width: 214px;
+ }
+
+ .rdw-colorpicker-modal {
+ width: auto;
+ }
+
+ .rdw-embedded-modal-btn,
+ .rdw-image-modal-btn,
+ .rdw-link-modal-btn {
+ height: 32px;
+ margin-top: 12px;
+ }
+
+ .rdw-embedded-modal-input,
+ .rdw-embedded-modal-size-input,
+ .rdw-link-modal-input {
+ padding: 2px 6px;
+ height: 32px;
+ }
+
+ .rdw-dropdown-selectedtext {
+ color: #000;
+ }
+
+ .rdw-dropdown-wrapper,
+ .rdw-option-wrapper {
+ min-width: 36px;
+ transition: all 0.2s ease;
+ height: 30px;
+
+ &:active {
+ box-shadow: 1px 1px 0 #e8e8e8 inset;
+ }
+
+ &:hover {
+ box-shadow: 1px 1px 0 #e8e8e8;
+ }
+ }
+
+ .rdw-dropdown-wrapper {
+ min-width: 60px;
+ }
+
+ .rdw-editor-main {
+ box-sizing: border-box;
+ }
+ }
+
+ .editor {
+ border: 1px solid #f1f1f1;
+ padding: 5px;
+ border-radius: 2px;
+ height: auto;
+ min-height: 200px;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/package.json b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/package.json
new file mode 100644
index 00000000..3ea063e3
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Editor/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "Editor",
+ "version": "0.0.0",
+ "private": true,
+ "main": "Editor.js"
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.d.ts b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.d.ts
new file mode 100644
index 00000000..075fa789
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.d.ts
@@ -0,0 +1,21 @@
+import React from 'react';
+import { TooltipProps } from 'antd/lib/tooltip';
+
+export interface EllipsisTooltipProps extends TooltipProps {
+ title?: undefined;
+ overlayStyle?: undefined;
+}
+
+export interface EllipsisProps {
+ tooltip?: boolean | EllipsisTooltipProps;
+ length?: number;
+ lines?: number;
+ style?: React.CSSProperties;
+ className?: string;
+ fullWidthRecognition?: boolean;
+}
+
+export function getStrFullLength(str: string): number;
+export function cutStrByFullLength(str: string, maxLength: number): string;
+
+export default class Ellipsis extends React.Component {}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.js
new file mode 100644
index 00000000..1fa1936c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.js
@@ -0,0 +1,262 @@
+import React, { Component } from 'react';
+import { Tooltip } from 'antd';
+import classNames from 'classnames';
+import styles from './index.module.less';
+
+/* eslint react/no-did-mount-set-state: 0 */
+/* eslint no-param-reassign: 0 */
+
+const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
+
+const TooltipOverlayStyle = {
+ overflowWrap: 'break-word',
+ wordWrap: 'break-word',
+};
+
+export const getStrFullLength = (str = '') =>
+ str.split('').reduce((pre, cur) => {
+ const charCode = cur.charCodeAt(0);
+ if (charCode >= 0 && charCode <= 128) {
+ return pre + 1;
+ }
+ return pre + 2;
+ }, 0);
+
+export const cutStrByFullLength = (str = '', maxLength) => {
+ let showLength = 0;
+ return str.split('').reduce((pre, cur) => {
+ const charCode = cur.charCodeAt(0);
+ if (charCode >= 0 && charCode <= 128) {
+ showLength += 1;
+ } else {
+ showLength += 2;
+ }
+ if (showLength <= maxLength) {
+ return pre + cur;
+ }
+ return pre;
+ }, '');
+};
+
+const getTooltip = ({ tooltip, overlayStyle, title, children }) => {
+ if (tooltip) {
+ const props = tooltip === true ? { overlayStyle, title } : { ...tooltip, overlayStyle, title };
+ return {children};
+ }
+ return children;
+};
+
+const EllipsisText = ({ text, length, tooltip, fullWidthRecognition, ...other }) => {
+ if (typeof text !== 'string') {
+ throw new Error('Ellipsis children must be string.');
+ }
+ const textLength = fullWidthRecognition ? getStrFullLength(text) : text.length;
+ if (textLength <= length || length < 0) {
+ return {text};
+ }
+ const tail = '...';
+ let displayText;
+ if (length - tail.length <= 0) {
+ displayText = '';
+ } else {
+ displayText = fullWidthRecognition ? cutStrByFullLength(text, length) : text.slice(0, length);
+ }
+
+ const spanAttrs = tooltip ? {} : { ...other };
+ return getTooltip({
+ tooltip,
+ overlayStyle: TooltipOverlayStyle,
+ title: text,
+ children: (
+
+ {displayText}
+ {tail}
+
+ ),
+ });
+};
+
+export default class Ellipsis extends Component {
+ state = {
+ text: '',
+ targetCount: 0,
+ };
+
+ componentDidMount() {
+ if (this.node) {
+ this.computeLine();
+ }
+ }
+
+ componentDidUpdate(perProps) {
+ const { lines } = this.props;
+ if (lines !== perProps.lines) {
+ this.computeLine();
+ }
+ }
+
+ computeLine = () => {
+ const { lines } = this.props;
+ if (lines && !isSupportLineClamp) {
+ const text = this.shadowChildren.innerText || this.shadowChildren.textContent;
+ const lineHeight = parseInt(getComputedStyle(this.root).lineHeight, 10);
+ const targetHeight = lines * lineHeight;
+ this.content.style.height = `${targetHeight}px`;
+ const totalHeight = this.shadowChildren.offsetHeight;
+ const shadowNode = this.shadow.firstChild;
+
+ if (totalHeight <= targetHeight) {
+ this.setState({
+ text,
+ targetCount: text.length,
+ });
+ return;
+ }
+
+ // bisection
+ const len = text.length;
+ const mid = Math.ceil(len / 2);
+
+ const count = this.bisection(targetHeight, mid, 0, len, text, shadowNode);
+
+ this.setState({
+ text,
+ targetCount: count,
+ });
+ }
+ };
+
+ bisection = (th, m, b, e, text, shadowNode) => {
+ const suffix = '...';
+ let mid = m;
+ let end = e;
+ let begin = b;
+ shadowNode.innerHTML = text.substring(0, mid) + suffix;
+ let sh = shadowNode.offsetHeight;
+
+ if (sh <= th) {
+ shadowNode.innerHTML = text.substring(0, mid + 1) + suffix;
+ sh = shadowNode.offsetHeight;
+ if (sh > th || mid === begin) {
+ return mid;
+ }
+ begin = mid;
+ if (end - begin === 1) {
+ mid = 1 + begin;
+ } else {
+ mid = Math.floor((end - begin) / 2) + begin;
+ }
+ return this.bisection(th, mid, begin, end, text, shadowNode);
+ }
+ if (mid - 1 < 0) {
+ return mid;
+ }
+ shadowNode.innerHTML = text.substring(0, mid - 1) + suffix;
+ sh = shadowNode.offsetHeight;
+ if (sh <= th) {
+ return mid - 1;
+ }
+ end = mid;
+ mid = Math.floor((end - begin) / 2) + begin;
+ return this.bisection(th, mid, begin, end, text, shadowNode);
+ };
+
+ handleRoot = n => {
+ this.root = n;
+ };
+
+ handleContent = n => {
+ this.content = n;
+ };
+
+ handleNode = n => {
+ this.node = n;
+ };
+
+ handleShadow = n => {
+ this.shadow = n;
+ };
+
+ handleShadowChildren = n => {
+ this.shadowChildren = n;
+ };
+
+ render() {
+ const { text, targetCount } = this.state;
+ const { children, lines, length, className, tooltip, fullWidthRecognition, ...restProps } = this.props;
+
+ const cls = classNames(styles.ellipsis, className, {
+ [styles.lines]: lines && !isSupportLineClamp,
+ [styles.lineClamp]: lines && isSupportLineClamp,
+ });
+
+ if (!lines && !length) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ // length
+ if (!lines) {
+ return (
+
+ );
+ }
+
+ const id = `antd-pro-ellipsis-${`${new Date().getTime()}${Math.floor(Math.random() * 100)}`}`;
+
+ // support document.body.style.webkitLineClamp
+ if (isSupportLineClamp) {
+ const style = `#${id}{-webkit-line-clamp:${lines};-webkit-box-orient: vertical;}`;
+
+ const node = (
+
+
+ {children}
+
+ );
+
+ return getTooltip({
+ tooltip,
+ overlayStyle: TooltipOverlayStyle,
+ title: children,
+ children: node,
+ });
+ }
+
+ const childNode = (
+
+ {targetCount > 0 && text.substring(0, targetCount)}
+ {targetCount > 0 && targetCount < text.length && '...'}
+
+ );
+
+ return (
+
+
+ {getTooltip({
+ tooltip,
+ overlayStyle: TooltipOverlayStyle,
+ title: text,
+ children: childNode,
+ })}
+
+ {children}
+
+
+ {text}
+
+
+
+ );
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.md b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.md
new file mode 100644
index 00000000..1875b17c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.md
@@ -0,0 +1,17 @@
+---
+title: Ellipsis
+subtitle: 文本自动省略号
+cols: 1
+order: 10
+---
+
+文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。
+
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+| -------------------- | ------------------------------------------------ | ------- | ------ |
+| tooltip | 移动到文本展示完整内容的提示 | boolean | - |
+| length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | - |
+| lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1` |
+| fullWidthRecognition | 是否将全角字符的长度视为 2 来计算字符串长度 | boolean | - |
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.module.less
new file mode 100644
index 00000000..3c0360c1
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.module.less
@@ -0,0 +1,24 @@
+.ellipsis {
+ display: inline-block;
+ width: 100%;
+ overflow: hidden;
+ word-break: break-all;
+}
+
+.lines {
+ position: relative;
+ .shadow {
+ position: absolute;
+ z-index: -999;
+ display: block;
+ color: transparent;
+ opacity: 0;
+ }
+}
+
+.lineClamp {
+ position: relative;
+ display: -webkit-box;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.test.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.test.js
new file mode 100644
index 00000000..4d057b24
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Ellipsis/index.test.js
@@ -0,0 +1,13 @@
+import { getStrFullLength, cutStrByFullLength } from './index';
+
+describe('test calculateShowLength', () => {
+ it('get full length', () => {
+ expect(getStrFullLength('一二,a,')).toEqual(8);
+ });
+ it('cut str by full length', () => {
+ expect(cutStrByFullLength('一二,a,', 7)).toEqual('一二,a');
+ });
+ it('cut str when length small', () => {
+ expect(cutStrByFullLength('一22三', 5)).toEqual('一22');
+ });
+});
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/FilterItem.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/FilterItem.js
new file mode 100644
index 00000000..ab54eed2
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/FilterItem.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './FilterItem.module.less';
+
+const FilterItem = ({ label = '', children }) => {
+ const labelArray = label.split('');
+ return (
+
+ {labelArray.length > 0 && (
+
+ {labelArray.map((item, index) => (
+
+ {item}
+
+ ))}
+
+ )}
+
{children}
+
+ );
+};
+
+FilterItem.propTypes = {
+ label: PropTypes.string,
+ children: PropTypes.element.isRequired,
+};
+
+export default FilterItem;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/FilterItem.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/FilterItem.module.less
new file mode 100644
index 00000000..c2e98ec5
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/FilterItem.module.less
@@ -0,0 +1,17 @@
+.filterItem {
+ display: flex;
+ justify-content: space-between;
+
+ .labelWrap {
+ width: 64px;
+ line-height: 28px;
+ margin-right: 12px;
+ justify-content: space-between;
+ display: flex;
+ overflow: hidden;
+ }
+
+ .item {
+ flex: 1;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/package.json b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/package.json
new file mode 100644
index 00000000..b266204f
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/FilterItem/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "FilterItem",
+ "version": "0.0.0",
+ "private": true,
+ "main": "FilterItem.js"
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.d.ts b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.d.ts
new file mode 100644
index 00000000..efde77db
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.d.ts
@@ -0,0 +1,14 @@
+import React from 'react';
+export interface GlobalFooterProps {
+ links?: Array<{
+ key?: string;
+ title: React.ReactNode;
+ href: string;
+ blankTarget?: boolean;
+ }>;
+ copyright?: React.ReactNode;
+ style?: React.CSSProperties;
+ className?: string;
+}
+
+export default class GlobalFooter extends React.Component {}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.js
new file mode 100644
index 00000000..f912e5ee
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import classNames from 'classnames';
+import styles from './index.module.less';
+
+const GlobalFooter = ({ className, links, copyright }) => {
+ const clsString = classNames(styles.globalFooter, className);
+ return (
+
+ );
+};
+
+export default GlobalFooter;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.md b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.md
new file mode 100644
index 00000000..5d6058f6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.md
@@ -0,0 +1,15 @@
+---
+title: GlobalFooter
+subtitle: 全局页脚
+cols: 1
+order: 7
+---
+
+页脚属于全局导航的一部分,作为对顶部导航的补充,通过传递数据控制展示内容。
+
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --------- | -------- | ---------------------------------------------------------------- | ------ |
+| links | 链接数据 | array<{ title: ReactNode, href: string, blankTarget?: boolean }> | - |
+| copyright | 版权信息 | ReactNode | - |
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.module.less
new file mode 100644
index 00000000..c9d375c2
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/GlobalFooter/index.module.less
@@ -0,0 +1,29 @@
+@import '../../../../node_modules/antd/lib/style/themes/default.less';
+
+.globalFooter {
+ margin: 48px 0 24px 0;
+ padding: 0 16px;
+ text-align: center;
+
+ .links {
+ margin-bottom: 8px;
+
+ a {
+ color: @text-color-secondary;
+ transition: all 0.3s;
+
+ &:not(:last-child) {
+ margin-right: 40px;
+ }
+
+ &:hover {
+ color: @text-color;
+ }
+ }
+ }
+
+ .copyright {
+ color: @text-color-secondary;
+ font-size: @font-size-base;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Bread.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Bread.js
new file mode 100644
index 00000000..0b410e62
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Bread.js
@@ -0,0 +1,51 @@
+import React, { Fragment } from 'react';
+import { Breadcrumb } from 'antd';
+import { Link } from 'react-router-dom';
+import { t } from 'utils/intl';
+import iconMap from 'utils/iconMap';
+
+import { pathToRegexp } from 'path-to-regexp';
+import { queryAncestors } from 'utils';
+import styles from './Bread.module.less';
+import { withRouter } from 'react-router-dom';
+
+function Bread({ routeList, history }) {
+ const generateBreadcrumbs = paths => {
+ return paths.map((item, key) => {
+ const content = item && (
+
+ {item.icon && {iconMap[item.icon]}}
+ {item.name}
+
+ );
+
+ return (
+ item && (
+
+ {paths.length - 1 !== key ? {content} : content}
+
+ )
+ );
+ });
+ };
+
+ // Find a route that matches the pathname.
+ const currentRoute = routeList.find(_ => _.route && pathToRegexp(_.route).exec(history.location.pathname));
+
+ // Find the breadcrumb navigation of the current route match and all its ancestors.
+ const paths =
+ history.location.pathname === '/'
+ ? [routeList[0]]
+ : currentRoute
+ ? queryAncestors(routeList, currentRoute, 'breadcrumbParentId').reverse()
+ : [
+ {
+ id: 404,
+ name: t`Not Found`,
+ },
+ ];
+
+ return {generateBreadcrumbs(paths)};
+}
+
+export default withRouter(Bread);
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Bread.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Bread.module.less
new file mode 100644
index 00000000..29f247b2
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Bread.module.less
@@ -0,0 +1,16 @@
+.bread {
+ margin-bottom: 24px !important;
+
+ :global {
+ .ant-breadcrumb {
+ display: flex;
+ align-items: center;
+ }
+ }
+}
+
+@media (max-width: 767px) {
+ .bread {
+ margin-bottom: 12px !important;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Header.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Header.js
new file mode 100644
index 00000000..a1f86941
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Header.js
@@ -0,0 +1,116 @@
+import React, { Fragment } from 'react';
+import { Menu, Layout, Avatar, Popover, List } from 'antd';
+import { Ellipsis } from 'components';
+import { RightOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
+import { Trans } from 'utils/intl';
+import { getLocale, setLocale } from 'utils';
+import moment from 'moment';
+import classnames from 'classnames';
+import config from 'config';
+import styles from './Header.module.less';
+
+const { SubMenu } = Menu;
+
+function Header({ fixed, avatar, username, collapsed, notifications, onCollapseChange, onAllNotificationsRead }) {
+ const rightContent = [
+ ,
+ ];
+
+ if (config.i18n) {
+ const { languages } = config.i18n;
+ const language = getLocale();
+ const currentLanguage = languages.find(item => item.key === language);
+
+ rightContent.unshift(
+
+ );
+ }
+
+ rightContent.unshift(
+ document.querySelector('#primaryLayout')}
+ content={
+
+
You have viewed all notifications.,
+ }}
+ renderItem={item => (
+
+
+ {item.title}
+
+ }
+ description={moment(item.date).fromNow()}
+ />
+
+
+ )}
+ />
+ {notifications.length ? (
+
+ Clear notifications
+
+ ) : null}
+
+ }
+ >
+ {/*
+
+ */}
+
+ );
+
+ return (
+
+ );
+}
+
+export default Header;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Header.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Header.module.less
new file mode 100644
index 00000000..4b487d66
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Header.module.less
@@ -0,0 +1,154 @@
+@import '../../themes/vars.less';
+
+.header {
+ padding: 0 !important;
+ box-shadow: @shadow-2;
+ position: relative;
+ display: flex;
+ justify-content: space-between;
+ height: 72px !important;
+ z-index: 9;
+ align-items: center;
+ background-color: #fff !important;
+
+ &.fixed {
+ position: fixed;
+ top: 0;
+ right: 0;
+ width: ~'calc(100% - 256px)';
+ z-index: 29;
+ transition: width 0.2s;
+
+ &.collapsed {
+ width: ~'calc(100% - 80px)';
+ }
+ }
+
+ :global {
+ .ant-menu-submenu-title {
+ height: 72px;
+ }
+
+ .ant-menu-horizontal {
+ line-height: 72px;
+
+ & > .ant-menu-submenu:hover {
+ color: @primary-color;
+ background-color: @hover-color;
+ }
+ }
+
+ .ant-menu {
+ border-bottom: none;
+ height: 72px;
+ }
+
+ .ant-menu-horizontal > .ant-menu-submenu {
+ top: 0;
+ margin-top: 0;
+ }
+
+ .ant-menu-horizontal > .ant-menu-item,
+ .ant-menu-horizontal > .ant-menu-submenu {
+ border-bottom: none;
+ }
+
+ .ant-menu-horizontal > .ant-menu-item-active,
+ .ant-menu-horizontal > .ant-menu-item-open,
+ .ant-menu-horizontal > .ant-menu-item-selected,
+ .ant-menu-horizontal > .ant-menu-item:hover,
+ .ant-menu-horizontal > .ant-menu-submenu-active,
+ .ant-menu-horizontal > .ant-menu-submenu-open,
+ .ant-menu-horizontal > .ant-menu-submenu-selected,
+ .ant-menu-horizontal > .ant-menu-submenu:hover {
+ border-bottom: none;
+ }
+ }
+
+ .rightContainer {
+ display: flex;
+ align-items: center;
+ }
+
+ .button {
+ width: 72px;
+ height: 72px;
+ line-height: 72px;
+ text-align: center;
+ font-size: 18px;
+ cursor: pointer;
+ transition: @transition-ease-in;
+
+ &:hover {
+ color: @primary-color;
+ background-color: @hover-color;
+ }
+ }
+}
+
+.iconButton {
+ width: 48px;
+ height: 48px;
+ display: flex !important;
+ justify-content: center;
+ align-items: center;
+ border-radius: 24px;
+ cursor: pointer;
+ .background-hover();
+
+ &:hover {
+ .iconFont {
+ color: @primary-color;
+ }
+ }
+
+ & + .iconButton {
+ margin-left: 8px;
+ }
+
+ .iconFont {
+ color: #b2b0c7;
+ font-size: 24px;
+ }
+}
+
+.notification {
+ padding: 24px 0;
+ width: 320px;
+ .notificationItem {
+ transition: all 0.3s;
+ padding: 12px 24px;
+ cursor: pointer;
+ &:hover {
+ background-color: @hover-color;
+ }
+ }
+ .clearButton {
+ text-align: center;
+ height: 48px;
+ line-height: 48px;
+ cursor: pointer;
+ .background-hover();
+ }
+}
+
+.notificationPopover {
+ :global {
+ .ant-popover-inner-content {
+ padding: 0;
+ }
+ .ant-popover-arrow {
+ display: none;
+ }
+ .ant-list-item-content {
+ flex: 0;
+ margin-left: 16px;
+ }
+ }
+}
+
+@media (max-width: 767px) {
+ .header {
+ width: 100% !important;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Sider.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Sider.js
new file mode 100644
index 00000000..5a8bab0b
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Sider.js
@@ -0,0 +1,64 @@
+import React from 'react';
+import { Switch, Layout } from 'antd';
+import { t } from 'utils/intl';
+import { Trans } from 'utils/intl';
+import { BulbOutlined } from '@ant-design/icons';
+import ScrollBar from '../ScrollBar';
+import config from 'utils/config';
+import SiderMenu from './SiderMenu';
+import styles from './Sider.module.less';
+
+function Sider({ menus, theme, isMobile, collapsed, onThemeChange, onCollapseChange }) {
+ return (
+
+
+
+

+ {!collapsed &&
{config.siteName}
}
+
+
+
+
+
+
+
+
+ {!collapsed && (
+
+
+
+ Switch Theme
+
+
+
+ )}
+
+ );
+}
+
+export default Sider;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Sider.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Sider.module.less
new file mode 100644
index 00000000..28dfa1fc
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/Sider.module.less
@@ -0,0 +1,114 @@
+@import '../../themes/vars.less';
+
+.sider {
+ box-shadow: fade(@primary-color, 10%) 0 0 28px 0;
+ z-index: 10;
+ :global {
+ .ant-layout-sider-children {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ }
+ }
+}
+
+.brand {
+ z-index: 1;
+ height: 72px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 24px;
+ box-shadow: 0 1px 9px -3px rgba(0, 0, 0, 0.2);
+ .logo {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ img {
+ width: 36px;
+ margin-right: 8px;
+ }
+
+ h1 {
+ vertical-align: text-bottom;
+ font-size: 16px;
+ text-transform: uppercase;
+ display: inline-block;
+ font-weight: 700;
+ color: @primary-color;
+ white-space: nowrap;
+ margin-bottom: 0;
+ .text-gradient();
+
+ :local {
+ animation: fadeRightIn 300ms @ease-in-out;
+ animation-fill-mode: both;
+ }
+ }
+ }
+}
+
+.menuContainer {
+ height: ~'calc(100vh - 120px)';
+ overflow-x: hidden;
+ flex: 1;
+ padding: 24px 0;
+
+ &::-webkit-scrollbar-thumb {
+ background-color: transparent;
+ }
+
+ &:hover {
+ &::-webkit-scrollbar-thumb {
+ background-color: rgba(0, 0, 0, 0.2);
+ }
+ }
+
+ :global {
+ .ant-menu-inline {
+ border-right: none;
+ }
+ }
+}
+
+.darkTheme {
+ color: rgb(102, 102, 102);
+}
+
+.switchTheme {
+ width: 100%;
+ height: 48px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 16px;
+ overflow: hidden;
+ transition: all 0.3s;
+
+ span {
+ white-space: nowrap;
+ overflow: hidden;
+ font-size: 12px;
+ }
+
+ :global {
+ .anticon {
+ min-width: 14px;
+ margin-right: 4px;
+ font-size: 14px;
+ }
+ }
+}
+
+@keyframes fadeLeftIn {
+ 0% {
+ transform: translateX(5px);
+ opacity: 0;
+ }
+
+ 100% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/SiderMenu.tsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/SiderMenu.tsx
new file mode 100644
index 00000000..80ddaa29
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/SiderMenu.tsx
@@ -0,0 +1,97 @@
+import React, { useState, Fragment } from 'react';
+import PropTypes from 'prop-types';
+import { Menu } from 'antd';
+import { NavLink } from 'react-router-dom';
+import { pathToRegexp } from 'path-to-regexp';
+import { arrayToTree, queryAncestors } from '../../utils';
+import iconMap from '../../utils/iconMap';
+import store from 'store';
+import { getStore } from '../../models/app-model';
+import { withRouter } from 'react-router-dom';
+
+const { SubMenu } = Menu;
+
+function SiderMenu({ theme, menus, history, isMobile, onCollapseChange }) {
+ const st = getStore();
+
+ const [openKeys, setOpenKeys] = useState(store.get('openKeys') || []);
+
+ const onOpenChange = openKeys => {
+ const rootSubmenuKeys = menus.filter(_ => !_.menuParentId).map(_ => _.id);
+
+ const latestOpenKey = openKeys.find(key => openKeys.indexOf(key) === -1);
+
+ let newOpenKeys = openKeys;
+ if (rootSubmenuKeys.indexOf(latestOpenKey) !== -1) {
+ newOpenKeys = latestOpenKey ? [latestOpenKey] : [];
+ }
+
+ setOpenKeys(newOpenKeys);
+
+ store.set('openKeys', newOpenKeys);
+ };
+
+ const generateMenus = data => {
+ return data.map(item => {
+ if (item.children) {
+ return (
+
+ {item.icon && iconMap[item.icon]}
+ {item.name}
+
+ }
+ >
+ {generateMenus(item.children)}
+
+ );
+ }
+ return (
+
+
+ {item.icon && iconMap[item.icon]}
+ {item.name}
+
+
+ );
+ });
+ };
+
+ // Generating tree-structured data for menu content.
+ const menuTree = arrayToTree(menus, 'id', 'menuParentId');
+
+ // Find a menu that matches the pathname.
+ const currentMenu = menus.find(_ => _.route && pathToRegexp(_.route).exec(history.location.pathname));
+
+ // Find the key that should be selected according to the current menu.
+ const selectedKeys = currentMenu ? queryAncestors(menus, currentMenu, 'menuParentId').map(_ => _.id) : [];
+
+ const menuProps = st.collapsed
+ ? {}
+ : {
+ openKeys: openKeys,
+ };
+
+ return (
+
+ );
+}
+
+export default withRouter(SiderMenu);
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/index.js
new file mode 100644
index 00000000..934351a8
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Layout/index.js
@@ -0,0 +1,6 @@
+import Header from './Header';
+import Menu from './SiderMenu';
+import Bread from './Bread';
+import Sider from './Sider';
+
+export { Header, Menu, Bread, Sider };
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/Loader.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/Loader.js
new file mode 100644
index 00000000..bf2f0c3c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/Loader.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import styles from './Loader.module.less';
+
+const Loader = ({ spinning = false, fullScreen }) => {
+ return (
+
+ );
+};
+
+Loader.propTypes = {
+ spinning: PropTypes.bool,
+ fullScreen: PropTypes.bool,
+};
+
+export default Loader;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/Loader.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/Loader.module.less
new file mode 100644
index 00000000..11b4d417
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/Loader.module.less
@@ -0,0 +1,69 @@
+.loader {
+ background-color: #fff;
+ width: 100%;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 100000;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ opacity: 1;
+ text-align: center;
+
+ &.fullScreen {
+ position: fixed;
+ }
+
+ .warpper {
+ width: 100px;
+ height: 100px;
+ display: inline-flex;
+ flex-direction: column;
+ justify-content: space-around;
+ }
+
+ .inner {
+ width: 40px;
+ height: 40px;
+ margin: 0 auto;
+ text-indent: -12345px;
+ border-top: 1px solid rgba(0, 0, 0, 0.08);
+ border-right: 1px solid rgba(0, 0, 0, 0.08);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+ border-left: 1px solid rgba(0, 0, 0, 0.7);
+ border-radius: 50%;
+ z-index: 100001;
+
+ :local {
+ animation: spinner 600ms infinite linear;
+ }
+ }
+
+ .text {
+ width: 100px;
+ height: 20px;
+ text-align: center;
+ font-size: 12px;
+ letter-spacing: 4px;
+ color: #000;
+ }
+
+ &.hidden {
+ z-index: -1;
+ opacity: 0;
+ transition:
+ opacity 1s ease 0.5s,
+ z-index 0.1s ease 1.5s;
+ }
+}
+@keyframes spinner {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/package.json b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/package.json
new file mode 100644
index 00000000..b1718b55
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Loader/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "Loader",
+ "version": "0.0.0",
+ "private": true,
+ "main": "Loader.js"
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/Page.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/Page.js
new file mode 100644
index 00000000..36c7f12e
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/Page.js
@@ -0,0 +1,33 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import Loader from '../Loader';
+import styles from './Page.module.less';
+
+export default class Page extends Component {
+ render() {
+ const { className, children, loading = false, inner = false } = this.props;
+ const loadingStyle = {
+ height: 'calc(100vh - 184px)',
+ overflow: 'hidden',
+ };
+ return (
+
+ {loading ? : ''}
+ {children}
+
+ );
+ }
+}
+
+Page.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.node,
+ loading: PropTypes.bool,
+ inner: PropTypes.bool,
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/Page.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/Page.module.less
new file mode 100644
index 00000000..fa8713aa
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/Page.module.less
@@ -0,0 +1,16 @@
+@import '../../themes/vars.less';
+
+.contentInner {
+ background: #fff;
+ padding: 24px;
+ box-shadow: @shadow-1;
+ min-height: ~'calc(100vh - 230px)';
+ position: relative;
+}
+
+@media (max-width: 767px) {
+ .contentInner {
+ padding: 12px;
+ min-height: ~'calc(100vh - 160px)';
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/package.json b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/package.json
new file mode 100644
index 00000000..0b7aa2d8
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/Page/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "Page",
+ "version": "0.0.0",
+ "private": true,
+ "main": "Page.js"
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/ScrollBar/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/ScrollBar/index.js
new file mode 100644
index 00000000..3b171ce6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/ScrollBar/index.js
@@ -0,0 +1,5 @@
+import ScrollBar from 'react-perfect-scrollbar';
+import 'react-perfect-scrollbar/dist/css/styles.css';
+import './index.less';
+
+export default ScrollBar;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/ScrollBar/index.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/ScrollBar/index.less
new file mode 100644
index 00000000..31e149bc
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/ScrollBar/index.less
@@ -0,0 +1,31 @@
+:global {
+ .ps--active-x > .ps__rail-x,
+ .ps--active-y > .ps__rail-y {
+ background-color: transparent;
+ }
+
+ .ps__rail-x:hover > .ps__thumb-x,
+ .ps__rail-x:focus > .ps__thumb-x {
+ height: 8px;
+ }
+
+ .ps__rail-y:hover > .ps__thumb-y,
+ .ps__rail-y:focus > .ps__thumb-y {
+ width: 8px;
+ }
+
+ .ps__rail-y,
+ .ps__rail-x {
+ z-index: 9;
+ }
+
+ .ps__thumb-y {
+ width: 4px;
+ right: 4px;
+ }
+
+ .ps__thumb-x {
+ height: 4px;
+ bottom: 4px;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/index.js
new file mode 100644
index 00000000..81a96eb2
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/components/index.js
@@ -0,0 +1,11 @@
+import Editor from './Editor';
+import FilterItem from './FilterItem';
+import DropOption from './DropOption';
+import Loader from './Loader';
+import ScrollBar from './ScrollBar';
+import GlobalFooter from './GlobalFooter';
+import Ellipsis from './Ellipsis';
+import * as MyLayout from './Layout';
+import Page from './Page';
+
+export { MyLayout, Editor, GlobalFooter, Ellipsis, FilterItem, DropOption, Loader, Page, ScrollBar };
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/BaseLayout.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/BaseLayout.js
new file mode 100644
index 00000000..e55716f4
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/BaseLayout.js
@@ -0,0 +1,29 @@
+import React, { Fragment } from 'react';
+import { Helmet } from 'react-helmet';
+import { queryLayout } from 'utils';
+import config from 'utils/config';
+
+import PublicLayout from './PublicLayout';
+import PrimaryLayout from './PrimaryLayout';
+import { withRouter } from 'react-router-dom';
+import './BaseLayout.less';
+
+const LayoutMap = {
+ primary: PrimaryLayout,
+ public: PublicLayout,
+};
+
+function BaseLayout({ children, location }) {
+ const Container = LayoutMap[queryLayout(config.layouts, location.pathname)];
+
+ return (
+
+
+ {config.siteName}
+
+ {children}
+
+ );
+}
+
+export default withRouter(BaseLayout);
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/BaseLayout.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/BaseLayout.less
new file mode 100644
index 00000000..ab1fdbd7
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/BaseLayout.less
@@ -0,0 +1,76 @@
+@import '../themes/vars.less';
+@import '../themes/index.less';
+
+:global {
+ #nprogress {
+ pointer-events: none;
+
+ .bar {
+ background: @primary-color;
+ position: fixed;
+ z-index: 2048;
+ top: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+ height: 2px;
+ }
+
+ .peg {
+ display: block;
+ position: absolute;
+ right: 0;
+ width: 100px;
+ height: 100%;
+ box-shadow:
+ 0 0 10px @primary-color,
+ 0 0 5px @primary-color;
+ opacity: 1;
+ transform: rotate(3deg) translate(0, -4px);
+ }
+
+ .spinner {
+ display: block;
+ position: fixed;
+ z-index: 1031;
+ top: 15px;
+ right: 15px;
+ }
+
+ .spinner-icon {
+ width: 18px;
+ height: 18px;
+ box-sizing: border-box;
+ border: solid 2px transparent;
+ border-top-color: @primary-color;
+ border-left-color: @primary-color;
+ border-radius: 50%;
+
+ :local {
+ animation: nprogress-spinner 400ms linear infinite;
+ }
+ }
+ }
+
+ .nprogress-custom-parent {
+ overflow: hidden;
+ position: relative;
+
+ #nprogress {
+ .bar,
+ .spinner {
+ position: absolute;
+ }
+ }
+ }
+}
+
+@keyframes nprogress-spinner {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PrimaryLayout.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PrimaryLayout.module.less
new file mode 100644
index 00000000..d10017fb
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PrimaryLayout.module.less
@@ -0,0 +1,58 @@
+@import '../themes/vars.less';
+
+.backTop {
+ right: 50px;
+
+ :global {
+ .ant-back-top-content {
+ background: @primary-color;
+ opacity: 0.3;
+ transition: all 0.3s;
+ box-shadow: 0 0 15px 1px rgba(69, 65, 78, 0.1);
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+ }
+}
+
+.content {
+ padding: 24px;
+ min-height: ~'calc(100% - 72px)';
+ // overflow-y: scroll;
+}
+
+.container {
+ height: 100vh;
+ flex: 1;
+ width: ~'calc(100% - 256px)';
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
+
+.footer {
+ background: #fff;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-top: 24px;
+ padding-bottom: 24px;
+ min-height: 72px;
+}
+
+@media (max-width: 767px) {
+ .content {
+ padding: 12px;
+ }
+
+ .backTop {
+ right: 20px;
+ bottom: 20px;
+ }
+
+ .container {
+ height: 100vh;
+ flex: 1;
+ width: 100%;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PrimaryLayout.tsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PrimaryLayout.tsx
new file mode 100644
index 00000000..465e1cf0
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PrimaryLayout.tsx
@@ -0,0 +1,100 @@
+import React, { useEffect, Fragment } from 'react';
+import PropTypes from 'prop-types';
+import { MyLayout, GlobalFooter } from '../components';
+import { BackTop, Layout, Drawer } from 'antd';
+
+import { pathToRegexp } from 'path-to-regexp';
+import { getLocale } from '../utils';
+import config from '../utils/config';
+import Error from '../pages/404';
+import styles from './PrimaryLayout.module.less';
+import store from 'store';
+import { getStore } from '../models/app-model';
+import { withRouter } from 'react-router-dom';
+
+const { Content } = Layout;
+const { Header, Bread, Sider } = MyLayout;
+
+function PrimaryLayout({ children, location, history }) {
+ const st = getStore();
+
+ useEffect(() => {
+ st.query(history);
+ }, []);
+
+ const onCollapseChange = collapsed => {
+ st.handleCollapseChange(collapsed);
+ };
+
+ const theme = st.theme;
+ const collapsed = st.collapsed;
+ const notifications = st.notifications;
+ const user = store.get('user') || {};
+ const permissions = st.permissions;
+ const routeList = st.routeList || [];
+
+ const lang = getLocale();
+
+ const newRouteList =
+ lang !== 'en'
+ ? routeList.map(item => {
+ const { name, ...other } = item;
+ return {
+ ...other,
+ name: (item[lang] || {}).name || name,
+ };
+ })
+ : routeList;
+
+ // Find a route that matches the pathname.
+ const currentRoute = newRouteList.find(_ => _.route && pathToRegexp(`${_.route}`).exec(location.pathname));
+
+ // Query whether you have permission to enter this page
+ const hasPermission = currentRoute ? permissions.visit.includes(currentRoute.id) : false;
+
+ // MenuParentId is equal to -1 is not a available menu.
+ const menus = newRouteList.filter(_ => _.menuParentId !== '-1');
+
+ const headerProps = {
+ menus,
+ collapsed,
+ notifications,
+ onCollapseChange,
+ avatar: user.avatar,
+ username: user.username,
+ fixed: config.fixedHeader,
+ onAllNotificationsRead: () => {
+ st.allNotificationsRead();
+ },
+ };
+
+ const siderProps = {
+ theme,
+ menus,
+ collapsed,
+ onCollapseChange,
+ onThemeChange: theme => {
+ st.handleThemeChange(theme);
+ },
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ {hasPermission ? children : }
+
+ document.querySelector('#primaryLayout')} />
+
+
+
+
+ );
+}
+
+export default withRouter(PrimaryLayout);
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PublicLayout.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PublicLayout.js
new file mode 100644
index 00000000..962ebb4e
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/PublicLayout.js
@@ -0,0 +1,3 @@
+export default ({ children }) => {
+ return children;
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/index.js
new file mode 100644
index 00000000..5b6b76c7
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/layouts/index.js
@@ -0,0 +1,34 @@
+import React, { Suspense } from 'react';
+import { ConfigProvider } from 'antd';
+import { IntlProvider } from 'react-intl';
+import { getLocale } from '../utils';
+import BaseLayout from './BaseLayout';
+import { Route, withRouter } from 'react-router-dom';
+import { getRoutes } from '../pages/routes';
+import { getLangResource } from '../utils/intl';
+
+function Layout() {
+ let language = getLocale();
+
+ let langResource = getLangResource(language);
+
+ const routes = getRoutes();
+
+ return (
+
+
+
+
+
+ {routes[0].childRoutes.map(item => {
+ return ;
+ })}
+
+
+
+
+
+ );
+}
+
+export default withRouter(Layout);
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/en/messages.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/en/messages.js
new file mode 100644
index 00000000..c6dbd55a
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/en/messages.js
@@ -0,0 +1,54 @@
+export default {
+ '/dashboard': '/dashboard',
+ 'Add Param': 'Add Param',
+ Address: 'Address',
+ Age: 'Age',
+ 'Are you sure delete this record?': 'Are you sure delete this record?',
+ Author: 'Author',
+ Avatar: 'Avatar',
+ Categories: 'Categories',
+ 'Clear notifications': 'Clear notifications',
+ Comments: 'Comments',
+ Create: 'Create',
+ 'Create User': 'Create User',
+ CreateTime: 'CreateTime',
+ Dark: 'Dark',
+ Delete: 'Delete',
+ Email: 'Email',
+ Female: 'Female',
+ Gender: 'Gender',
+ 'Hi,': 'Hi,',
+ Image: 'Image',
+ Light: 'Light',
+ Male: 'Male',
+ Name: 'Name',
+ NickName: 'NickName',
+ 'Not Found': 'Not Found',
+ Operation: 'Operation',
+ Params: 'Params',
+ Password: 'Password',
+ Phone: 'Phone',
+ 'Pick an address': 'Pick an address',
+ 'Please pick an address': 'Please pick an address',
+ Published: 'Published',
+ 'Publish Date': 'Publish Date',
+ Reset: 'Reset',
+ Search: 'Search',
+ 'Search Name': 'Search Name',
+ Send: 'Send',
+ 'Sign in': 'Sign in',
+ 'Sign out': 'Sign out',
+ 'Switch Theme': 'Switch Theme',
+ Tags: 'Tags',
+ 'The input is not valid E-mail!': 'The input is not valid E-mail!',
+ 'The input is not valid phone!': 'The input is not valid phone!',
+ Title: 'Title',
+ Total: 'Total {total} Items',
+ Unpublished: 'Unpublished',
+ Update: 'Update',
+ 'Update User': 'Update User',
+ Username: 'Username',
+ Views: 'Views',
+ Visibility: 'Visibility',
+ 'You have viewed all notifications.': 'You have viewed all notifications.',
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/pt-br/messages.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/pt-br/messages.js
new file mode 100644
index 00000000..bbbab040
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/pt-br/messages.js
@@ -0,0 +1,54 @@
+export default {
+ '/dashboard': '/dashboard',
+ 'Add Param': 'Add Parametro',
+ Address: 'Endereço',
+ Age: 'Ano',
+ 'Are you sure delete this record?': 'Tem certeza de excluir este registro?',
+ Author: 'Autor',
+ Avatar: 'Avatar',
+ Categories: 'Categorias',
+ 'Clear notifications': 'limpar notificações',
+ Comments: 'Comentarios',
+ Create: 'Criar',
+ 'Create User': 'Criar Usuário',
+ CreateTime: 'CreateTime',
+ Dark: 'Escuro',
+ Delete: 'Deletar',
+ Email: 'Email',
+ Female: 'Feminino',
+ Gender: 'Genero',
+ 'Hi,': 'Olá,',
+ Image: 'Imagem',
+ Light: 'Claro',
+ Male: 'masculino',
+ Name: 'Nome',
+ NickName: 'NickName',
+ 'Not Found': 'Não Encontrado',
+ Operation: 'Operation',
+ Params: 'Parametros',
+ Password: 'Senha',
+ Phone: 'Fone',
+ 'Pick an address': 'Escolha um endereço',
+ 'Please pick an address': 'Por favor, escolha um endereço',
+ Published: 'Publicado',
+ 'Publish Date': 'Data de publicação',
+ Reset: 'Reset',
+ Search: 'procurar',
+ 'Search Name': 'Search Name',
+ Send: 'Enviar',
+ 'Sign in': 'Sign in',
+ 'Sign out': 'Sign out',
+ 'Switch Theme': 'Trocar tema',
+ Tags: 'Tags',
+ 'The input is not valid E-mail!': 'Não é um E-mail valido!',
+ 'The input is not valid phone!': 'Não é um telefone Valido!',
+ Title: 'Titulo',
+ Total: 'Total {total} Items',
+ Unpublished: 'Não publicado',
+ Update: 'Atualizar',
+ 'Update User': 'Atualizar Usuário',
+ Username: 'Usuário',
+ Views: 'visualizações',
+ Visibility: 'Visibilidade',
+ 'You have viewed all notifications.': 'Você visualizou todas as notificações.',
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/zh/messages.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/zh/messages.js
new file mode 100644
index 00000000..fb51ae8c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/locales/zh/messages.js
@@ -0,0 +1,54 @@
+export default {
+ '/dashboard': '/zh/dashboard',
+ 'Add Param': '添加参数',
+ Address: '地址',
+ Age: '年龄',
+ 'Are you sure delete this record?': '您确定要删除这条记录吗?',
+ Author: '作者',
+ Avatar: '头像',
+ Categories: '类别',
+ 'Clear notifications': '清空消息',
+ Comments: '评论数',
+ Create: '创建',
+ 'Create User': '创建用户',
+ CreateTime: '创建时间',
+ Dark: '暗',
+ Delete: '删除',
+ Email: '电子邮件',
+ Female: '女',
+ Gender: '性别',
+ 'Hi,': '你好,',
+ Image: '图像',
+ Light: '明',
+ Male: '男性',
+ Name: '名字',
+ NickName: '昵称',
+ 'Not Found': '未找到',
+ Operation: '操作',
+ Params: '参数',
+ Password: '密码',
+ Phone: '电话',
+ 'Pick an address': '选择地址',
+ 'Please pick an address': '选择地址',
+ Published: '已发布',
+ 'Publish Date': '发布日期',
+ Reset: '重置',
+ Search: '搜索',
+ 'Search Name': '搜索名字',
+ Send: '发送',
+ 'Sign in': '登录',
+ 'Sign out': '退出登录',
+ 'Switch Theme': '切换主题',
+ Tags: '标签',
+ 'The input is not valid E-mail!': '输入的电子邮件无效!',
+ 'The input is not valid phone!': '输入无效的手机!',
+ Title: '标题',
+ Total: '总共 {total} 条记录',
+ Unpublished: '未发布',
+ Update: '更新',
+ 'Update User': '更新用户',
+ Username: '用户名',
+ Views: '浏览数',
+ Visibility: '可见性',
+ 'You have viewed all notifications.': '您已查看所有通知',
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/main.jsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/main.jsx
new file mode 100644
index 00000000..c285ca91
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/main.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import ReactDom from 'react-dom';
+import { BrowserRouter } from 'react-router-dom';
+
+import 'antd/dist/antd.css';
+
+import Layout from './layouts';
+
+ReactDom.render(
+
+
+ ,
+ document.getElementsByTagName('body')[0]
+);
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/models/app-model.ts b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/models/app-model.ts
new file mode 100644
index 00000000..f7ae9c81
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/models/app-model.ts
@@ -0,0 +1,82 @@
+import { stringify } from 'qs';
+import store from 'store';
+import { pathToRegexp } from 'path-to-regexp';
+import { ROLE_TYPE } from '../utils/constant';
+import { queryLayout } from '../utils';
+import api from '../services';
+import config from '../utils/config';
+// @ts-ignore
+const { queryRouteList, queryUserInfo } = api;
+
+import { createStore } from 'inula';
+
+const goDashboard = history => {
+ if (pathToRegexp(['/', '/login']).exec(window.location.pathname)) {
+ history.push({
+ pathname: '/dashboard',
+ });
+ }
+};
+
+export const getStore = createStore({
+ id: 'app',
+ state: {
+ routeList: [],
+ permissions: { visit: [] },
+ locationPathname: '',
+ locationQuery: {},
+ theme: store.get('theme') || 'light',
+ collapsed: store.get('collapsed') || false,
+ notifications: [
+ {
+ title: 'New User is registered.',
+ date: new Date(Date.now() - 10000000),
+ },
+ {
+ title: 'Application has been approved.',
+ date: new Date(Date.now() - 50000000),
+ },
+ ],
+ },
+ actions: {
+ handleThemeChange(state, val) {
+ store.set('theme', val);
+ state.theme = val;
+ },
+
+ handleCollapseChange(state, val) {
+ store.set('collapsed', val);
+ state.collapsed = val;
+ },
+
+ allNotificationsRead(state) {
+ state.notifications = [];
+ },
+
+ async query(state, history) {
+ const locationPathname = state.locationPathname;
+ const { success, user } = await queryUserInfo();
+ if (success && user) {
+ const { list } = await queryRouteList();
+ const { permissions } = user;
+ let routeList = list;
+ if (permissions.role === ROLE_TYPE.ADMIN || permissions.role === ROLE_TYPE.DEVELOPER) {
+ permissions.visit = list.map(item => item.id);
+ } else {
+ routeList = list.filter(item => {
+ const cases = [
+ permissions.visit.includes(item.id),
+ item.mpid ? permissions.visit.includes(item.mpid) || item.mpid === '-1' : true,
+ item.bpid ? permissions.visit.includes(item.bpid) : true,
+ ];
+ return cases.every(_ => _);
+ });
+ }
+ state.routeList = routeList;
+ state.permissions = permissions;
+ store.set('user', user);
+ goDashboard(history);
+ }
+ },
+ },
+});
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/404.jsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/404.jsx
new file mode 100644
index 00000000..6720f6ef
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/404.jsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { FrownOutlined } from '@ant-design/icons';
+import { Page } from 'components';
+import styles from './404.module.less';
+
+const Error = () => (
+
+
+
+
404 Not Found
+
+
+);
+
+export default Error;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/404.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/404.module.less
new file mode 100644
index 00000000..f5300b1f
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/404.module.less
@@ -0,0 +1,19 @@
+.error {
+ color: black;
+ text-align: center;
+ position: absolute;
+ top: 30%;
+ margin-top: -50px;
+ left: 50%;
+ margin-left: -100px;
+ width: 200px;
+
+ :global .anticon {
+ font-size: 48px;
+ margin-bottom: 16px;
+ }
+
+ h1 {
+ font-family: cursive;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/browser.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/browser.js
new file mode 100644
index 00000000..955c1643
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/browser.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Table, Tag } from 'antd';
+import Color from 'utils/theme';
+import styles from './browser.module.less';
+
+const status = {
+ 1: {
+ color: Color.green,
+ },
+ 2: {
+ color: Color.red,
+ },
+ 3: {
+ color: Color.blue,
+ },
+ 4: {
+ color: Color.yellow,
+ },
+};
+
+function Browser({ data }) {
+ const columns = [
+ {
+ title: 'name',
+ dataIndex: 'name',
+ className: styles.name,
+ },
+ {
+ title: 'percent',
+ dataIndex: 'percent',
+ className: styles.percent,
+ render: (text, it) => {text}%,
+ },
+ ];
+ return ;
+}
+
+Browser.propTypes = {
+ data: PropTypes.array,
+};
+
+export default Browser;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/browser.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/browser.module.less
new file mode 100644
index 00000000..631ad64f
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/browser.module.less
@@ -0,0 +1,7 @@
+.percent {
+ text-align: right !important;
+}
+
+.name {
+ text-align: left !important;
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/comments.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/comments.js
new file mode 100644
index 00000000..e5eb8551
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/comments.js
@@ -0,0 +1,63 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Table, Tag } from 'antd';
+import Color from '../../../utils/theme';
+import styles from './comments.module.less';
+
+const status = {
+ 1: {
+ color: Color.green,
+ text: 'APPROVED',
+ },
+ 2: {
+ color: Color.yellow,
+ text: 'PENDING',
+ },
+ 3: {
+ color: Color.red,
+ text: 'REJECTED',
+ },
+};
+
+function Comments({ data }) {
+ const columns = [
+ {
+ title: 'avatar',
+ dataIndex: 'avatar',
+ width: 48,
+ className: styles.avatarcolumn,
+ render: text => ,
+ },
+ {
+ title: 'content',
+ dataIndex: 'content',
+ render: (text, it) => (
+
+
{it.name}
+
{it.content}
+
+ {status[it.status].text}
+ {it.date}
+
+
+ ),
+ },
+ ];
+ return (
+
+
key < 3)}
+ />
+
+ );
+}
+
+Comments.propTypes = {
+ data: PropTypes.array,
+};
+
+export default Comments;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/comments.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/comments.module.less
new file mode 100644
index 00000000..f6fa2dec
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/comments.module.less
@@ -0,0 +1,43 @@
+@import '../../../themes/vars.less';
+
+.comments {
+ :global .ant-table-thead > tr > th {
+ background: #fff;
+ border-bottom: solid 1px @border-color-base;
+ }
+
+ .avatar {
+ width: 48px;
+ height: 48px;
+ background-position: center;
+ background-size: cover;
+ border-radius: 50%;
+ background: #f8f8f8;
+ display: inline-block;
+ }
+
+ .content {
+ text-align: left;
+ color: #757575;
+ }
+
+ .date {
+ color: #a3a3a3;
+ line-height: 30px;
+ }
+
+ .daterow {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .name {
+ font-size: 14px;
+ color: #474747;
+ text-align: left;
+ }
+
+ .avatarcolumn {
+ vertical-align: top;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/completed.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/completed.js
new file mode 100644
index 00000000..06908f3c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/completed.js
@@ -0,0 +1,86 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import Color from 'utils/theme';
+import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
+import styles from './completed.module.less';
+
+function Completed({ data }) {
+ return (
+
+
TEAM TOTAL COMPLETED
+
+
+
+
+
+ );
+}
+
+Completed.propTypes = {
+ data: PropTypes.array,
+};
+
+export default Completed;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/completed.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/completed.module.less
new file mode 100644
index 00000000..4dc79a16
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/completed.module.less
@@ -0,0 +1,49 @@
+@import '../../../themes/vars.less';
+
+.sales {
+ .title {
+ margin-left: 32px;
+ font-size: 16px;
+ }
+}
+
+.radiusdot {
+ width: 12px;
+ height: 12px;
+ margin-right: 8px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.legend {
+ text-align: right;
+ color: #999;
+ font-size: 14px;
+
+ li {
+ height: 48px;
+ line-height: 48px;
+ display: inline-block;
+
+ & + li {
+ margin-left: 24px;
+ }
+ }
+}
+
+.tooltip {
+ background: #fff;
+ padding: 20px;
+ font-size: 14px;
+
+ .tiptitle {
+ font-weight: 700;
+ font-size: 16px;
+ margin-bottom: 8px;
+ }
+
+ .tipitem {
+ height: 32px;
+ line-height: 32px;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/cpu.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/cpu.js
new file mode 100644
index 00000000..81dea61c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/cpu.js
@@ -0,0 +1,58 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Color from 'utils/theme';
+import CountUp from 'react-countup';
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from 'recharts';
+import styles from './cpu.module.less';
+
+const countUpProps = {
+ start: 0,
+ duration: 2.75,
+ useEasing: true,
+ useGrouping: true,
+ separator: ',',
+};
+
+function Cpu({ usage = 0, space = 0, cpu = 0, data }) {
+ return (
+
+ );
+}
+
+Cpu.propTypes = {
+ data: PropTypes.array,
+ usage: PropTypes.number,
+ space: PropTypes.number,
+ cpu: PropTypes.number,
+};
+
+export default Cpu;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/cpu.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/cpu.module.less
new file mode 100644
index 00000000..d23163b1
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/cpu.module.less
@@ -0,0 +1,40 @@
+.cpu {
+ .number {
+ display: flex;
+ height: 64px;
+ justify-content: space-between;
+ margin-bottom: 32px;
+
+ .item {
+ text-align: center;
+ height: 64px;
+ width: 100%;
+ position: relative;
+
+ & + .item {
+ &::before {
+ content: '';
+ display: block;
+ width: 1px;
+ height: 40px;
+ position: absolute;
+ background: #f5f5f5;
+ top: 12px;
+ }
+ }
+
+ p {
+ color: #757575;
+
+ &:first-child {
+ font-size: 16px;
+ }
+
+ &:last-child {
+ font-size: 20px;
+ font-weight: 700;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/index.js
new file mode 100644
index 00000000..f52fc524
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/index.js
@@ -0,0 +1,12 @@
+import NumberCard from './numberCard';
+import Quote from './quote';
+import Sales from './sales';
+import Weather from './weather';
+import RecentSales from './recentSales';
+import Comments from './comments';
+import Completed from './completed';
+import Browser from './browser';
+import Cpu from './cpu';
+import User from './user';
+
+export { NumberCard, Quote, Sales, Weather, RecentSales, Comments, Completed, Browser, Cpu, User };
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/numberCard.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/numberCard.js
new file mode 100644
index 00000000..204c9faf
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/numberCard.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Card } from 'antd';
+import CountUp from 'react-countup';
+import iconMap from 'utils/iconMap';
+import styles from './numberCard.module.less';
+
+function NumberCard({ icon, color, title, number, countUp }) {
+ return (
+
+
+ {iconMap[icon]}
+
+
+
{title || 'No Title'}
+
+
+
+
+
+ );
+}
+
+NumberCard.propTypes = {
+ icon: PropTypes.string,
+ color: PropTypes.string,
+ title: PropTypes.string,
+ number: PropTypes.number,
+ countUp: PropTypes.object,
+};
+
+export default NumberCard;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/numberCard.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/numberCard.module.less
new file mode 100644
index 00000000..b8c74ca8
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/numberCard.module.less
@@ -0,0 +1,33 @@
+@import '../../../themes/vars';
+
+.numberCard {
+ padding: 32px;
+ margin-bottom: 24px;
+ cursor: pointer;
+
+ .iconWarp {
+ font-size: 54px;
+ float: left;
+ }
+
+ .content {
+ width: 100%;
+ padding-left: 78px;
+
+ .title {
+ line-height: 16px;
+ font-size: 16px;
+ margin-bottom: 8px;
+ height: 16px;
+ .text-overflow();
+ }
+
+ .number {
+ line-height: 32px;
+ font-size: 24px;
+ height: 32px;
+ .text-overflow();
+ margin-bottom: 0;
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/quote.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/quote.js
new file mode 100644
index 00000000..a0a12d0c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/quote.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './quote.module.less';
+
+function Quote({ name, content, title, avatar }) {
+ return (
+
+ );
+}
+
+Quote.propTypes = {
+ name: PropTypes.string,
+ content: PropTypes.string,
+ title: PropTypes.string,
+ avatar: PropTypes.string,
+};
+
+export default Quote;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/quote.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/quote.module.less
new file mode 100644
index 00000000..7d60b714
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/quote.module.less
@@ -0,0 +1,52 @@
+@import '../../../themes/vars';
+
+.quote {
+ color: #fff;
+ height: 100%;
+ width: 100%;
+ padding: 24px;
+ font-size: 16px;
+ font-weight: 700;
+
+ .inner {
+ text-overflow: ellipsis;
+ word-wrap: normal;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 4;
+ overflow: hidden;
+ text-indent: 24px;
+ }
+
+ .footer {
+ position: relative;
+ margin-top: 14px;
+
+ .description {
+ width: 100%;
+
+ p {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ margin-right: 64px;
+ text-align: right;
+
+ &:last-child {
+ font-weight: 100;
+ }
+ }
+ }
+
+ .avatar {
+ width: 48px;
+ height: 48px;
+ background-position: center;
+ background-size: cover;
+ border-radius: 50%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/recentSales.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/recentSales.js
new file mode 100644
index 00000000..8ba3d6b6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/recentSales.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import moment from 'moment';
+import PropTypes from 'prop-types';
+import { Table, Tag } from 'antd';
+import Color from '../../../utils/theme';
+import styles from './recentSales.module.less';
+
+const status = {
+ 1: {
+ color: Color.green,
+ text: 'SALE',
+ },
+ 2: {
+ color: Color.yellow,
+ text: 'REJECT',
+ },
+ 3: {
+ color: Color.red,
+ text: 'TAX',
+ },
+ 4: {
+ color: Color.blue,
+ text: 'EXTENDED',
+ },
+};
+
+function RecentSales({ data }) {
+ const columns = [
+ {
+ title: 'NAME',
+ dataIndex: 'name',
+ },
+ {
+ title: 'STATUS',
+ dataIndex: 'status',
+ render: text => {status[text].text},
+ },
+ {
+ title: 'DATE',
+ dataIndex: 'date',
+ render: text => moment(text).format('YYYY-MM-DD'),
+ },
+ {
+ title: 'PRICE',
+ dataIndex: 'price',
+ render: (text, it) => ${text},
+ },
+ ];
+ return (
+
+
key < 5)} />
+
+ );
+}
+
+RecentSales.propTypes = {
+ data: PropTypes.array,
+};
+
+export default RecentSales;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/recentSales.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/recentSales.module.less
new file mode 100644
index 00000000..ac9aea34
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/recentSales.module.less
@@ -0,0 +1,8 @@
+@import '../../../themes/vars';
+
+.recentsales {
+ :global .ant-table-thead > tr > th {
+ background: #fff;
+ border-bottom: solid 1px @border-color-base;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/sales.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/sales.js
new file mode 100644
index 00000000..4556e04c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/sales.js
@@ -0,0 +1,93 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import Color from '../../../utils/theme';
+// import { Color } from '../../../utils/theme';
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
+import styles from './sales.module.less';
+
+function Sales({ data }) {
+ return (
+
+
Yearly Sales
+
+
+
+
+
+ );
+}
+
+Sales.propTypes = {
+ data: PropTypes.array,
+};
+
+export default Sales;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/sales.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/sales.module.less
new file mode 100644
index 00000000..5de99060
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/sales.module.less
@@ -0,0 +1,50 @@
+@import '../../../themes/vars';
+
+.sales {
+ overflow: hidden;
+ .title {
+ margin-left: 32px;
+ font-size: 16px;
+ }
+}
+
+.radiusdot {
+ width: 12px;
+ height: 12px;
+ margin-right: 8px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.legend {
+ text-align: right;
+ color: #999;
+ font-size: 14px;
+
+ li {
+ height: 48px;
+ line-height: 48px;
+ display: inline-block;
+
+ & + li {
+ margin-left: 24px;
+ }
+ }
+}
+
+.tooltip {
+ background: #fff;
+ padding: 20px;
+ font-size: 14px;
+
+ .tiptitle {
+ font-weight: 700;
+ font-size: 16px;
+ margin-bottom: 8px;
+ }
+
+ .tipitem {
+ height: 32px;
+ line-height: 32px;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user-background.png b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user-background.png
new file mode 100644
index 00000000..5f99e137
Binary files /dev/null and b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user-background.png differ
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user.js
new file mode 100644
index 00000000..8ad9be7b
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Button, Avatar } from 'antd';
+import CountUp from 'react-countup';
+import Color from 'utils/theme';
+import styles from './user.module.less';
+
+const countUpProps = {
+ start: 0,
+ duration: 2.75,
+ useEasing: true,
+ useGrouping: true,
+ separator: ',',
+};
+
+function User({ avatar, username, sales = 0, sold = 0 }) {
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+User.propTypes = {
+ avatar: PropTypes.string,
+ username: PropTypes.string,
+ sales: PropTypes.number,
+ sold: PropTypes.number,
+};
+
+export default User;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user.module.less
new file mode 100644
index 00000000..cfcc51b2
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/user.module.less
@@ -0,0 +1,88 @@
+@import '../../../themes/vars';
+
+.user {
+ .header {
+ display: flex;
+ justify-content: center;
+ text-align: center;
+ color: #fff;
+ height: 200px;
+ background-size: cover;
+ align-items: center;
+
+ .headerinner {
+ z-index: 2;
+ }
+
+ &::after {
+ content: '';
+ background-image: url('user-background.png');
+ background-size: cover;
+ position: absolute;
+ width: 100%;
+ height: 200px;
+ left: 0;
+ top: 0;
+ opacity: 0.4;
+ z-index: 1;
+ }
+
+ .name {
+ font-size: 16px;
+ margin-top: 8px;
+ }
+ }
+
+ .number {
+ display: flex;
+ height: 116px;
+ justify-content: space-between;
+ border-bottom: solid 1px #f5f5f5;
+
+ .item {
+ text-align: center;
+ height: 116px;
+ width: 100%;
+ position: relative;
+ padding: 30px 0;
+
+ & + .item {
+ &::before {
+ content: '';
+ display: block;
+ width: 1px;
+ height: 116px;
+ position: absolute;
+ background: #f5f5f5;
+ top: 0;
+ }
+ }
+
+ p {
+ color: #757575;
+
+ &:first-child {
+ font-size: 16px;
+ }
+
+ &:last-child {
+ font-size: 20px;
+ font-weight: 700;
+ }
+ }
+ }
+ }
+
+ .footer {
+ height: 116px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ :global .ant-btn {
+ color: @purple;
+ border-color: @purple;
+ padding: 6px 16px;
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/weather.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/weather.js
new file mode 100644
index 00000000..8a5acf03
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/weather.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Spin } from 'antd';
+import styles from './weather.module.less';
+
+function Weather({ city, icon, dateTime, temperature, name, loading }) {
+ return (
+
+
+
+
+
{`${temperature}°`}
+
+ {city},{dateTime}
+
+
+
+
+ );
+}
+
+Weather.propTypes = {
+ city: PropTypes.string,
+ icon: PropTypes.string,
+ dateTime: PropTypes.string,
+ temperature: PropTypes.string,
+ name: PropTypes.string,
+ loading: PropTypes.bool,
+};
+
+export default Weather;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/weather.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/weather.module.less
new file mode 100644
index 00000000..5ebec21c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/components/weather.module.less
@@ -0,0 +1,48 @@
+@import '../../../themes/vars';
+
+.weather {
+ color: #fff;
+ height: 204px;
+ padding: 24px;
+ justify-content: space-between;
+ display: flex;
+ font-size: 14px;
+
+ .left {
+ display: flex;
+ flex-direction: column;
+ width: 64px;
+ padding-top: 55px;
+
+ .icon {
+ width: 64px;
+ height: 64px;
+ background-position: center;
+ background-size: contain;
+ }
+
+ p {
+ margin-top: 16px;
+ }
+ }
+
+ .right {
+ display: flex;
+ flex-direction: column;
+ width: 50%;
+
+ .temperature {
+ font-size: 36px;
+ text-align: right;
+ height: 64px;
+ color: #fff;
+ }
+
+ .description {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-align: right;
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/index.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/index.module.less
new file mode 100644
index 00000000..596b1c45
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/index.module.less
@@ -0,0 +1,27 @@
+.dashboard {
+ position: relative;
+ :global {
+ .ant-card {
+ border-radius: 0;
+ margin-bottom: 24px;
+ &:hover {
+ box-shadow: 4px 4px 40px rgba(0, 0, 0, 0.05);
+ }
+ }
+ .ant-card-body {
+ overflow-x: hidden;
+ }
+ }
+
+ .weather {
+ &:hover {
+ box-shadow: 4px 4px 40px rgba(143, 201, 251, 0.6);
+ }
+ }
+
+ .quote {
+ &:hover {
+ box-shadow: 4px 4px 40px rgba(246, 152, 153, 0.6);
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/index.tsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/index.tsx
new file mode 100644
index 00000000..3bf72938
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/index.tsx
@@ -0,0 +1,134 @@
+import React, { useEffect } from 'react';
+import { Row, Col, Card } from 'antd';
+import Color from '../../utils/theme';
+import { Page, ScrollBar } from '../../components';
+import { NumberCard, Quote, Sales, Weather, RecentSales, Comments, Completed, Browser, Cpu, User } from './components';
+import styles from './index.module.less';
+import store from 'store';
+import { getStore } from './model';
+
+const bodyStyle = {
+ bodyStyle: {
+ height: 432,
+ background: '#fff',
+ },
+};
+
+function Dashboard() {
+ const st = getStore();
+
+ useEffect(() => {
+ st.query();
+ }, []);
+
+ const userDetail = store.get('user');
+ const { avatar, username } = userDetail;
+
+ const weather = st.weather;
+ const sales = st.sales;
+ const quote = st.quote;
+ const numbers = st.numbers;
+ const recentSales = st.recentSales;
+ const comments = st.comments;
+ const completed = st.completed;
+ const browser = st.browser;
+ const cpu = st.cpu;
+ const user = st.user;
+
+ const numberCards = numbers.map((item, key) => (
+
+
+
+ ));
+
+ return (
+
+
+ {numberCards}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
+
+
+
+
+
+
+
+
+
+ */}
+ {/*
+
+
+
+ */}
+ {/*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ */}
+
+
+ );
+}
+
+export default Dashboard;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/model.ts b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/model.ts
new file mode 100644
index 00000000..72e5e19a
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/model.ts
@@ -0,0 +1,69 @@
+import { parse } from 'qs';
+import api from '../../services';
+
+import { pathToRegexp } from 'path-to-regexp';
+import { createStore } from 'inula';
+
+const { queryDashboard, queryWeather } = api;
+const avatar = '//cdn.antd-admin.zuiidea.com/bc442cf0cc6f7940dcc567e465048d1a8d634493198c4-sPx5BR_fw236.jpeg';
+
+export const getStore = createStore({
+ id: 'dashboard',
+ state: {
+ weather: {
+ city: '深圳',
+ temperature: '30',
+ name: '晴',
+ icon: '//cdn.antd-admin.zuiidea.com/sun.png',
+ },
+ message: null,
+ sales: [],
+ quote: {
+ avatar,
+ },
+ numbers: [],
+ recentSales: [],
+ comments: [],
+ completed: [],
+ browser: [],
+ cpu: {},
+ user: {
+ avatar,
+ },
+ loading: false,
+ },
+ actions: {
+ async query(state, payload) {
+ state.loading = true;
+ const data = await queryDashboard(parse(payload));
+ state.loading = false;
+
+ state.browser = data.browser;
+ state.comments = data.comments;
+ state.completed = data.completed;
+ state.cpu = data.cpu;
+ state.message = data.message;
+ state.numbers = data.numbers;
+ state.quote = data.quote;
+ state.recentSales = data.recentSales;
+ state.sales = data.sales;
+ state.user = data.user;
+ },
+ async queryWeather(state, payload = {}) {
+ payload.location = 'shenzhen';
+ const result = await queryWeather(payload);
+ const { success } = result;
+ if (success) {
+ const data = result.results[0];
+ const weather = {
+ city: data.location.name,
+ temperature: data.now.temperature,
+ name: data.now.text,
+ icon: `//cdn.antd-admin.zuiidea.com/web/icons/3d_50/${data.now.code}.png`,
+ };
+
+ state.weather = weather;
+ }
+ },
+ },
+});
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/services/dashboard.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/services/dashboard.js
new file mode 100644
index 00000000..b832a809
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/services/dashboard.js
@@ -0,0 +1,12 @@
+import { request, config } from 'utils';
+
+const { api } = config;
+const { dashboard } = api;
+
+export function query(params) {
+ return request({
+ url: dashboard,
+ method: 'get',
+ data: params,
+ });
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/services/weather.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/services/weather.js
new file mode 100644
index 00000000..4af783e4
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/dashboard/services/weather.js
@@ -0,0 +1,12 @@
+import { request, config } from 'utils';
+
+const { APIV1 } = config;
+
+export function query(params) {
+ params.key = 'i7sau1babuzwhycn';
+ return request({
+ url: `${APIV1}/weather/now.json`,
+ method: 'get',
+ data: params,
+ });
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/index.js
new file mode 100644
index 00000000..fd5d3b25
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/index.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import { Redirect } from 'react-router-dom';
+
+function Index() {
+ return ;
+}
+
+export default Index;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/routes.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/routes.js
new file mode 100644
index 00000000..cb7e03c2
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/routes.js
@@ -0,0 +1,26 @@
+import React, { lazy } from 'react';
+
+export function getRoutes() {
+ const routes = [
+ {
+ path: '/',
+ component: lazy(() => import(/* webpackChunkName: 'layouts__index' */ '@/layouts/index.js')),
+ childRoutes: [
+ {
+ path: '/404',
+ component: lazy(() => import(/* webpackChunkName: 'p__404' */ '@/pages/404.jsx')),
+ },
+ {
+ path: '/dashboard',
+ component: lazy(() => import(/* webpackChunkName: 'p__dashboard__index' */ './dashboard/index.tsx')),
+ },
+ {
+ path: '/user',
+ component: lazy(() => import(/* webpackChunkName: 'p__user__index' */ '@/pages/user/index.tsx')),
+ },
+ ],
+ },
+ ];
+
+ return routes;
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Filter.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Filter.js
new file mode 100644
index 00000000..3138a2ff
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Filter.js
@@ -0,0 +1,114 @@
+import React, { useRef } from 'react';
+import moment from 'moment';
+import { FilterItem } from 'components';
+import { Button, Row, Col, DatePicker, Form, Input, Cascader } from 'antd';
+import city from 'utils/city';
+import { Trans, t } from 'utils/intl';
+import styles from './Filter.module.less';
+
+const { Search } = Input;
+const { RangePicker } = DatePicker;
+
+const ColProps = {
+ xs: 24,
+ sm: 12,
+ style: {
+ marginBottom: 16,
+ },
+};
+
+const TwoColProps = {
+ ...ColProps,
+ xl: 96,
+};
+
+function Filter({ onFilterChange, onAdd, filter }) {
+ const formRef = useRef();
+
+ const handleFields = fields => {
+ const { createTime } = fields;
+ if (createTime && createTime.length) {
+ fields.createTime = [moment(createTime[0]).format('YYYY-MM-DD'), moment(createTime[1]).format('YYYY-MM-DD')];
+ }
+ return fields;
+ };
+
+ const handleSubmit = () => {
+ const values = formRef.current.getFieldsValue();
+ const fields = handleFields(values);
+ onFilterChange(fields);
+ };
+
+ const handleReset = () => {
+ const fields = formRef.current.getFieldsValue();
+ for (let item in fields) {
+ if ({}.hasOwnProperty.call(fields, item)) {
+ if (fields[item] instanceof Array) {
+ fields[item] = [];
+ } else {
+ fields[item] = undefined;
+ }
+ }
+ }
+ formRef.current.setFieldsValue(fields);
+ handleSubmit();
+ };
+
+ const handleChange = (key, values) => {
+ let fields = formRef.current.getFieldsValue();
+ fields[key] = values;
+ fields = handleFields(fields);
+ onFilterChange(fields);
+ };
+
+ const { name, address } = filter;
+
+ let initialCreateTime = [];
+ if (filter.createTime && filter.createTime[0]) {
+ initialCreateTime[0] = moment(filter.createTime[0]);
+ }
+ if (filter.createTime && filter.createTime[1]) {
+ initialCreateTime[1] = moment(filter.createTime[1]);
+ }
+
+ return (
+
+ );
+}
+
+export default Filter;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Filter.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Filter.module.less
new file mode 100644
index 00000000..0cd55ada
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Filter.module.less
@@ -0,0 +1,3 @@
+.margin-right {
+ margin-right: 16px;
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/List.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/List.js
new file mode 100644
index 00000000..4ca59147
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/List.js
@@ -0,0 +1,113 @@
+import React from 'react';
+import { Table, Modal, Avatar } from 'antd';
+import { DropOption } from 'components';
+import { t } from 'utils/intl';
+import { Trans } from 'utils/intl';
+import { Link } from 'react-router-dom';
+import styles from './List.module.less';
+
+const { confirm } = Modal;
+
+function List({ onDeleteItem, onEditItem, ...tableProps }) {
+ const handleMenuClick = (record, e) => {
+ if (e.key === '1') {
+ onEditItem(record);
+ } else if (e.key === '2') {
+ confirm({
+ title: t`Are you sure delete this record?`,
+ onOk() {
+ onDeleteItem(record.id);
+ },
+ });
+ }
+ };
+
+ const columns = [
+ {
+ title: Avatar,
+ dataIndex: 'avatar',
+ key: 'avatar',
+ width: '7%',
+ fixed: 'left',
+ render: text => ,
+ },
+ {
+ title: Name,
+ dataIndex: 'name',
+ key: 'name',
+ },
+ {
+ title: NickName,
+ dataIndex: 'nickName',
+ key: 'nickName',
+ },
+ {
+ title: Age,
+ dataIndex: 'age',
+ width: '6%',
+ key: 'age',
+ },
+ {
+ title: Gender,
+ dataIndex: 'isMale',
+ key: 'isMale',
+ width: '7%',
+ render: text => {text ? 'Male' : 'Female'},
+ },
+ {
+ title: Phone,
+ dataIndex: 'phone',
+ key: 'phone',
+ },
+ {
+ title: Email,
+ dataIndex: 'email',
+ key: 'email',
+ },
+ {
+ title: Address,
+ dataIndex: 'address',
+ key: 'address',
+ },
+ {
+ title: CreateTime,
+ dataIndex: 'createTime',
+ key: 'createTime',
+ },
+ {
+ title: Operation,
+ key: 'operation',
+ fixed: 'right',
+ width: '8%',
+ render: (text, record) => {
+ return (
+ handleMenuClick(record, e)}
+ menuOptions={[
+ { key: '1', name: t`Update` },
+ { key: '2', name: t`Delete` },
+ ]}
+ />
+ );
+ },
+ },
+ ];
+
+ return (
+ t(`Total`, { total }),
+ }}
+ className={styles.table}
+ bordered
+ scroll={{ x: 1200 }}
+ columns={columns}
+ simple
+ rowKey={record => record.id}
+ />
+ );
+}
+
+export default List;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/List.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/List.module.less
new file mode 100644
index 00000000..6d35765f
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/List.module.less
@@ -0,0 +1,7 @@
+.table {
+ :global {
+ .ant-table td {
+ white-space: nowrap;
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Modal.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Modal.js
new file mode 100644
index 00000000..a90e4dc3
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/components/Modal.js
@@ -0,0 +1,95 @@
+import React, { useRef } from 'react';
+import { Form, Input, InputNumber, Radio, Modal, Cascader } from 'antd';
+import { t, Trans } from 'utils/intl';
+import city from 'utils/city';
+
+const FormItem = Form.Item;
+
+const formItemLayout = {
+ labelCol: {
+ span: 6,
+ },
+ wrapperCol: {
+ span: 14,
+ },
+};
+
+function UserModal({ item = {}, onOk, form, ...modalProps }) {
+ const formRef = useRef();
+
+ const handleOk = () => {
+ formRef.current
+ .validateFields()
+ .then(values => {
+ const data = {
+ ...values,
+ key: item.key,
+ };
+ data.address = data.address.join(' ');
+ onOk(data);
+ })
+ .catch(errorInfo => {
+ console.log(errorInfo);
+ });
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default UserModal;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/index.js
new file mode 100644
index 00000000..62293580
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/index.js
@@ -0,0 +1,33 @@
+import React, { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+import { Page } from 'components';
+import styles from './index.module.less';
+
+class UserDetail extends PureComponent {
+ render() {
+ const { userDetail } = this.props;
+ const { data } = userDetail;
+ const content = [];
+ for (let key in data) {
+ if ({}.hasOwnProperty.call(data, key)) {
+ content.push(
+
+
{key}
+
{String(data[key])}
+
+ );
+ }
+ }
+ return (
+
+ {content}
+
+ );
+ }
+}
+
+UserDetail.propTypes = {
+ userDetail: PropTypes.object,
+};
+
+export default UserDetail;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/index.module.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/index.module.less
new file mode 100644
index 00000000..fa9c7d40
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/index.module.less
@@ -0,0 +1,14 @@
+.content {
+ line-height: 2.4;
+ font-size: 13px;
+
+ .item {
+ display: flex;
+
+ & > div {
+ &:first-child {
+ width: 100px;
+ }
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/models/detail.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/models/detail.js
new file mode 100644
index 00000000..4b73d369
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/id/models/detail.js
@@ -0,0 +1,50 @@
+const { pathToRegexp } = require('path-to-regexp');
+import api from 'api';
+
+const { queryUser } = api;
+
+export default {
+ namespace: 'userDetail',
+
+ state: {
+ data: {},
+ },
+
+ subscriptions: {
+ setup({ dispatch, history }) {
+ history.listen(({ pathname }) => {
+ const match = pathToRegexp('/user/:id').exec(pathname);
+ if (match) {
+ dispatch({ type: 'query', payload: { id: match[1] } });
+ }
+ });
+ },
+ },
+
+ effects: {
+ *query({ payload }, { call, put }) {
+ const data = yield call(queryUser, payload);
+ const { success, message, status, ...other } = data;
+ if (success) {
+ yield put({
+ type: 'querySuccess',
+ payload: {
+ data: other,
+ },
+ });
+ } else {
+ throw data;
+ }
+ },
+ },
+
+ reducers: {
+ querySuccess(state, { payload }) {
+ const { data } = payload;
+ return {
+ ...state,
+ data,
+ };
+ },
+ },
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/index.tsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/index.tsx
new file mode 100644
index 00000000..b76db303
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/index.tsx
@@ -0,0 +1,148 @@
+import React, { useEffect } from 'react';
+import { Row, Col, Button, Popconfirm } from 'antd';
+import { Page } from '../../components';
+import { stringify } from 'qs';
+import List from './components/List';
+import Filter from './components/Filter';
+import Modal from './components/Modal';
+import { getStore } from './model';
+import { pathToRegexp } from 'path-to-regexp';
+import { t } from '../../utils/intl';
+import { parseSearch } from '../../utils';
+
+function User({ location, history }) {
+ const st = getStore();
+
+ useEffect(() => {
+ if (pathToRegexp('/user').exec(location.pathname)) {
+ const payload = { page: 1, pageSize: 10, ...parseSearch(location.search) };
+ st.query(payload);
+ }
+ }, [st.pagination.total]);
+
+ const handleRefresh = newQuery => {
+ const { search, pathname } = location;
+
+ const params = {
+ ...parseSearch(search),
+ ...newQuery,
+ };
+
+ history.push({
+ pathname,
+ search: stringify(params, { arrayFormat: 'repeat' }),
+ });
+
+ st.query(params);
+ };
+
+ const handleDeleteItems = () => {
+ st.multiDelete({
+ ids: st.selectedRowKeys,
+ });
+
+ handleRefresh({
+ page:
+ st.list.length === st.selectedRowKeys.length && st.pagination.current > 1
+ ? st.pagination.current - 1
+ : st.pagination.current,
+ });
+ };
+
+ const modalProps = () => {
+ return {
+ item: st.modalType === 'create' ? {} : st.currentItem,
+ visible: st.modalVisible,
+ destroyOnClose: true,
+ maskClosable: false,
+ confirmLoading: false,
+ title: `${st.modalType === 'create' ? t`Create User` : t`Update User`}`,
+ centered: true,
+ onOk: data => {
+ st[st.modalType](data);
+ handleRefresh();
+ },
+ onCancel() {
+ st.hideModal();
+ },
+ };
+ };
+
+ const listProps = () => {
+ return {
+ dataSource: st.list,
+ loading: false,
+ pagination: st.pagination,
+ onChange: page => {
+ const { search } = location;
+ const params = {
+ ...parseSearch(search),
+ page: page.current,
+ pageSize: page.pageSize,
+ };
+
+ handleRefresh(params);
+ },
+ onDeleteItem: id => {
+ st.delete(id);
+ handleRefresh({
+ page: st.list.length === 1 && st.pagination.current > 1 ? st.pagination.current - 1 : st.pagination.current,
+ });
+ },
+ onEditItem: item => {
+ st.showModal({
+ modalType: 'update',
+ currentItem: item,
+ });
+ },
+ rowSelection: {
+ selectedRowKeys: st.selectedRowKeys,
+ onChange: keys => {
+ st.selectedRowKeys = keys;
+ },
+ },
+ };
+ };
+
+ const filterProps = () => {
+ const { search } = location;
+
+ return {
+ filter: {
+ ...parseSearch(search),
+ },
+ onFilterChange: value => {
+ handleRefresh({
+ ...value,
+ });
+ },
+ onAdd: () => {
+ st.showModal({
+ modalType: 'create',
+ });
+ },
+ };
+ };
+
+ return (
+
+
+ {st.selectedRowKeys.length > 0 && (
+
+
+ {`Selected ${st.selectedRowKeys.length} items `}
+
+
+
+
+
+ )}
+
+
+
+ );
+}
+
+export default User;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/model.ts b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/model.ts
new file mode 100644
index 00000000..44f8ac24
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/pages/user/model.ts
@@ -0,0 +1,92 @@
+import api from '../../services';
+import { createStore } from 'inula';
+
+const { queryUserList, createUser, removeUser, updateUser, removeUserList } = api;
+
+export const getStore = createStore({
+ id: 'user',
+
+ state: {
+ currentItem: {
+ id: 0,
+ },
+ modalVisible: false,
+ modalType: 'create',
+ selectedRowKeys: [],
+
+ list: [],
+ pagination: {
+ showSizeChanger: true,
+ showQuickJumper: true,
+ current: 1,
+ total: 0,
+ pageSize: 10,
+ },
+ loading: false,
+ },
+
+ actions: {
+ async query(state, payload) {
+ state.loading = true;
+ const data = await queryUserList(payload);
+ state.loading = false;
+ if (data) {
+ state.list = data.data;
+ state.pagination.current = Number(payload.page) || 1;
+ state.pagination.pageSize = Number(payload.pageSize) || 10;
+ state.pagination.total = data.total;
+ }
+ },
+
+ async delete(state, payload) {
+ const data = await removeUser({ id: payload });
+ if (data.success) {
+ state.selectedRowKeys = state.selectedRowKeys.filter(_ => _ !== payload);
+ } else {
+ throw data;
+ }
+ },
+
+ async multiDelete(state, payload) {
+ const data = await removeUserList(payload);
+ if (data.success) {
+ state.selectedRowKeys = [];
+ } else {
+ throw data;
+ }
+ },
+
+ async create(state, payload) {
+ const data = await createUser(payload);
+ if (data.success) {
+ this.hideModal();
+ } else {
+ throw data;
+ }
+ },
+
+ async update(state, payload) {
+ const newUser = { ...payload, id: state.currentItem.id };
+ const data = await updateUser(newUser);
+ if (data.success) {
+ this.hideModal();
+ } else {
+ throw data;
+ }
+ },
+
+ showModal(state, payload) {
+ state.modalVisible = true;
+ if (state.modalType !== undefined) {
+ state.modalType = payload.modalType;
+ }
+ if (payload.currentItem !== undefined) {
+ state.currentItem = payload.currentItem;
+ }
+ },
+
+ hideModal(state) {
+ state.modalVisible = false;
+ },
+ },
+});
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/plugins/onError.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/plugins/onError.js
new file mode 100644
index 00000000..f9cb6260
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/plugins/onError.js
@@ -0,0 +1,13 @@
+import { message } from 'antd';
+
+export default {
+ onError(e, a) {
+ e.preventDefault();
+ if (e.message) {
+ message.error(e.message);
+ } else {
+ /* eslint-disable */
+ console.error(e);
+ }
+ },
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/services/api.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/services/api.js
new file mode 100644
index 00000000..1dddf50f
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/services/api.js
@@ -0,0 +1,16 @@
+export default {
+ queryRouteList: '/routes',
+
+ queryUserInfo: '/user',
+
+ queryUser: '/user/:id',
+ queryUserList: '/users',
+ updateUser: 'Patch /user/:id',
+ createUser: 'POST /user',
+ removeUser: 'DELETE /user/:id',
+ removeUserList: 'POST /users/delete',
+
+ queryPostList: '/posts',
+
+ queryDashboard: '/dashboard',
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/services/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/services/index.js
new file mode 100644
index 00000000..ef4c9bf1
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/services/index.js
@@ -0,0 +1,38 @@
+import request from 'utils/request';
+import config from 'utils/config';
+
+import api from './api';
+
+const gen = params => {
+ let url = config.apiPrefix + params;
+ let method = 'GET';
+
+ const paramsArray = params.split(' ');
+ if (paramsArray.length === 2) {
+ method = paramsArray[0];
+ url = config.apiPrefix + paramsArray[1];
+ }
+
+ return function (data) {
+ return request({
+ url,
+ data,
+ method,
+ });
+ };
+};
+
+const APIFunction = {};
+for (const key in api) {
+ APIFunction[key] = gen(api[key]);
+}
+
+APIFunction.queryWeather = params => {
+ params.key = 'i7sau1babuzwhycn';
+ return request({
+ url: `${config.apiPrefix}/weather/now.json`,
+ data: params,
+ });
+};
+
+export default APIFunction;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/default.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/default.less
new file mode 100644
index 00000000..78678a50
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/default.less
@@ -0,0 +1,16 @@
+// 本文件是对 ant-design:
+// https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
+// 相应变量值的覆盖
+// 注意:只需写出要覆盖的变量即可(不需要覆盖的变量不要写)
+
+@import '../../../node_modules/antd/lib/style/themes/default.less';
+
+@border-radius-base: 3px;
+@border-radius-sm: 2px;
+@shadow-color: rgba(0, 0, 0, 0.05);
+@shadow-1-down: 4px 4px 40px @shadow-color;
+@border-color-split: #f4f4f4;
+@border-color-base: #e5e5e5;
+@font-size-base: 13px;
+@text-color: #666;
+@hover-color: #f9f9fc;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/index.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/index.less
new file mode 100644
index 00000000..9b0df9b6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/index.less
@@ -0,0 +1,124 @@
+@import './vars.less';
+
+body {
+ height: 100%;
+ overflow-y: hidden;
+ background-color: #f8f8f8;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: #e6e6e6;
+}
+
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+.margin-right {
+ margin-right: 16px;
+}
+
+:global {
+ .ant-breadcrumb {
+ & > span {
+ &:last-child {
+ color: #999;
+ font-weight: normal;
+ }
+ }
+ }
+
+ .ant-breadcrumb-link {
+ .anticon + span {
+ margin-left: 4px;
+ }
+ }
+
+ .ant-table {
+ .ant-table-thead > tr > th {
+ text-align: center;
+ }
+
+ .ant-table-tbody > tr > td {
+ text-align: center;
+ }
+
+ &.ant-table-small {
+ .ant-table-thead > tr > th {
+ background: #f7f7f7;
+ }
+
+ .ant-table-body > table {
+ padding: 0;
+ }
+ }
+ }
+
+ .ant-table-pagination {
+ float: none !important;
+ display: table;
+ margin: 16px auto !important;
+ }
+
+ .ant-popover-inner {
+ border: none;
+ border-radius: 0;
+ box-shadow: 0 0 20px rgba(100, 100, 100, 0.2);
+ }
+
+ .ant-form-item-control {
+ vertical-align: middle;
+ }
+
+ .ant-modal-mask {
+ background-color: rgba(55, 55, 55, 0.2);
+ }
+
+ .ant-modal-content {
+ box-shadow: none;
+ }
+
+ .ant-select-dropdown-menu-item {
+ padding: 12px 16px !important;
+ }
+
+ a:focus {
+ text-decoration: none;
+ }
+
+ .ant-table-layout-fixed table {
+ table-layout: auto;
+ }
+}
+@media (min-width: 1600px) {
+ :global {
+ .ant-col-xl-48 {
+ width: 20%;
+ }
+
+ .ant-col-xl-96 {
+ width: 40%;
+ }
+ }
+}
+@media (max-width: 767px) {
+ :global {
+ .ant-pagination-item,
+ .ant-pagination-next,
+ .ant-pagination-options,
+ .ant-pagination-prev {
+ margin-bottom: 8px;
+ }
+
+ .ant-card {
+ .ant-card-head {
+ padding: 0 12px;
+ }
+
+ .ant-card-body {
+ padding: 12px;
+ }
+ }
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/mixin.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/mixin.less
new file mode 100644
index 00000000..dc01f6b6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/mixin.less
@@ -0,0 +1,35 @@
+@import './default.less';
+
+@dark-half: #494949;
+@purple: #d897eb;
+@shadow-1: 4px 4px 20px 0 rgba(0, 0, 0, 0.01);
+@shadow-2: 4px 4px 40px 0 rgba(0, 0, 0, 0.05);
+@transition-ease-in: all 0.3s ease-out;
+@transition-ease-out: all 0.3s ease-out;
+@ease-in: ease-in;
+
+.text-overflow {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.text-gradient {
+ background-image: -webkit-gradient(
+ linear,
+ 37.219838% 34.532506%,
+ 36.425669% 93.178216%,
+ from(#29cdff),
+ to(#0a60ff),
+ color-stop(0.37, #148eff)
+ );
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+.background-hover {
+ transition: @transition-ease-in;
+ &:hover {
+ background-color: @hover-color;
+ }
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/vars.less b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/vars.less
new file mode 100644
index 00000000..b8bb2bc6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/themes/vars.less
@@ -0,0 +1,2 @@
+@import './default.less';
+@import './mixin.less';
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/city.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/city.js
new file mode 100644
index 00000000..78aa870d
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/city.js
@@ -0,0 +1,4051 @@
+/*
+ ## Address 字典数据
+ 字典数据来源 http://www.atatech.org/articles/30028?rnd=254259856
+ 国标 省(市)级行政区划码表
+ 华北 北京市 天津市 河北省 山西省 内蒙古自治区
+ 东北 辽宁省 吉林省 黑龙江省
+ 华东 上海市 江苏省 浙江省 安徽省 福建省 江西省 山东省
+ 华南 广东省 广西壮族自治区 海南省
+ 华中 河南省 湖北省 湖南省
+ 西南 重庆市 四川省 贵州省 云南省 西藏自治区
+ 西北 陕西省 甘肃省 青海省 宁夏回族自治区 新疆维吾尔自治区
+ 港澳台 香港特别行政区 澳门特别行政区 台湾省
+
+ **排序**
+
+ ```js
+ var map = {}
+ _.each(_.keys(REGIONS),function(id){
+ map[id] = REGIONS[ID]
+ })
+ JSON.stringify(map)
+ ```
+*/
+let DICT = {
+ 110000: '北京',
+ 110100: '北京市',
+ 110101: '东城区',
+ 110102: '西城区',
+ 110105: '朝阳区',
+ 110106: '丰台区',
+ 110107: '石景山区',
+ 110108: '海淀区',
+ 110109: '门头沟区',
+ 110111: '房山区',
+ 110112: '通州区',
+ 110113: '顺义区',
+ 110114: '昌平区',
+ 110115: '大兴区',
+ 110116: '怀柔区',
+ 110117: '平谷区',
+ 110228: '密云县',
+ 110229: '延庆县',
+ 110230: '其它区',
+ 120000: '天津',
+ 120100: '天津市',
+ 120101: '和平区',
+ 120102: '河东区',
+ 120103: '河西区',
+ 120104: '南开区',
+ 120105: '河北区',
+ 120106: '红桥区',
+ 120110: '东丽区',
+ 120111: '西青区',
+ 120112: '津南区',
+ 120113: '北辰区',
+ 120114: '武清区',
+ 120115: '宝坻区',
+ 120116: '滨海新区',
+ 120221: '宁河县',
+ 120223: '静海县',
+ 120225: '蓟县',
+ 120226: '其它区',
+ 130000: '河北省',
+ 130100: '石家庄市',
+ 130102: '长安区',
+ 130103: '桥东区',
+ 130104: '桥西区',
+ 130105: '新华区',
+ 130107: '井陉矿区',
+ 130108: '裕华区',
+ 130121: '井陉县',
+ 130123: '正定县',
+ 130124: '栾城县',
+ 130125: '行唐县',
+ 130126: '灵寿县',
+ 130127: '高邑县',
+ 130128: '深泽县',
+ 130129: '赞皇县',
+ 130130: '无极县',
+ 130131: '平山县',
+ 130132: '元氏县',
+ 130133: '赵县',
+ 130181: '辛集市',
+ 130182: '藁城市',
+ 130183: '晋州市',
+ 130184: '新乐市',
+ 130185: '鹿泉市',
+ 130186: '其它区',
+ 130200: '唐山市',
+ 130202: '路南区',
+ 130203: '路北区',
+ 130204: '古冶区',
+ 130205: '开平区',
+ 130207: '丰南区',
+ 130208: '丰润区',
+ 130223: '滦县',
+ 130224: '滦南县',
+ 130225: '乐亭县',
+ 130227: '迁西县',
+ 130229: '玉田县',
+ 130230: '曹妃甸区',
+ 130281: '遵化市',
+ 130283: '迁安市',
+ 130284: '其它区',
+ 130300: '秦皇岛市',
+ 130302: '海港区',
+ 130303: '山海关区',
+ 130304: '北戴河区',
+ 130321: '青龙满族自治县',
+ 130322: '昌黎县',
+ 130323: '抚宁县',
+ 130324: '卢龙县',
+ 130398: '其它区',
+ 130400: '邯郸市',
+ 130402: '邯山区',
+ 130403: '丛台区',
+ 130404: '复兴区',
+ 130406: '峰峰矿区',
+ 130421: '邯郸县',
+ 130423: '临漳县',
+ 130424: '成安县',
+ 130425: '大名县',
+ 130426: '涉县',
+ 130427: '磁县',
+ 130428: '肥乡县',
+ 130429: '永年县',
+ 130430: '邱县',
+ 130431: '鸡泽县',
+ 130432: '广平县',
+ 130433: '馆陶县',
+ 130434: '魏县',
+ 130435: '曲周县',
+ 130481: '武安市',
+ 130482: '其它区',
+ 130500: '邢台市',
+ 130502: '桥东区',
+ 130503: '桥西区',
+ 130521: '邢台县',
+ 130522: '临城县',
+ 130523: '内丘县',
+ 130524: '柏乡县',
+ 130525: '隆尧县',
+ 130526: '任县',
+ 130527: '南和县',
+ 130528: '宁晋县',
+ 130529: '巨鹿县',
+ 130530: '新河县',
+ 130531: '广宗县',
+ 130532: '平乡县',
+ 130533: '威县',
+ 130534: '清河县',
+ 130535: '临西县',
+ 130581: '南宫市',
+ 130582: '沙河市',
+ 130583: '其它区',
+ 130600: '保定市',
+ 130602: '新市区',
+ 130603: '北市区',
+ 130604: '南市区',
+ 130621: '满城县',
+ 130622: '清苑县',
+ 130623: '涞水县',
+ 130624: '阜平县',
+ 130625: '徐水县',
+ 130626: '定兴县',
+ 130627: '唐县',
+ 130628: '高阳县',
+ 130629: '容城县',
+ 130630: '涞源县',
+ 130631: '望都县',
+ 130632: '安新县',
+ 130633: '易县',
+ 130634: '曲阳县',
+ 130635: '蠡县',
+ 130636: '顺平县',
+ 130637: '博野县',
+ 130638: '雄县',
+ 130681: '涿州市',
+ 130682: '定州市',
+ 130683: '安国市',
+ 130684: '高碑店市',
+ 130699: '其它区',
+ 130700: '张家口市',
+ 130702: '桥东区',
+ 130703: '桥西区',
+ 130705: '宣化区',
+ 130706: '下花园区',
+ 130721: '宣化县',
+ 130722: '张北县',
+ 130723: '康保县',
+ 130724: '沽源县',
+ 130725: '尚义县',
+ 130726: '蔚县',
+ 130727: '阳原县',
+ 130728: '怀安县',
+ 130729: '万全县',
+ 130730: '怀来县',
+ 130731: '涿鹿县',
+ 130732: '赤城县',
+ 130733: '崇礼县',
+ 130734: '其它区',
+ 130800: '承德市',
+ 130802: '双桥区',
+ 130803: '双滦区',
+ 130804: '鹰手营子矿区',
+ 130821: '承德县',
+ 130822: '兴隆县',
+ 130823: '平泉县',
+ 130824: '滦平县',
+ 130825: '隆化县',
+ 130826: '丰宁满族自治县',
+ 130827: '宽城满族自治县',
+ 130828: '围场满族蒙古族自治县',
+ 130829: '其它区',
+ 130900: '沧州市',
+ 130902: '新华区',
+ 130903: '运河区',
+ 130921: '沧县',
+ 130922: '青县',
+ 130923: '东光县',
+ 130924: '海兴县',
+ 130925: '盐山县',
+ 130926: '肃宁县',
+ 130927: '南皮县',
+ 130928: '吴桥县',
+ 130929: '献县',
+ 130930: '孟村回族自治县',
+ 130981: '泊头市',
+ 130982: '任丘市',
+ 130983: '黄骅市',
+ 130984: '河间市',
+ 130985: '其它区',
+ 131000: '廊坊市',
+ 131002: '安次区',
+ 131003: '广阳区',
+ 131022: '固安县',
+ 131023: '永清县',
+ 131024: '香河县',
+ 131025: '大城县',
+ 131026: '文安县',
+ 131028: '大厂回族自治县',
+ 131081: '霸州市',
+ 131082: '三河市',
+ 131083: '其它区',
+ 131100: '衡水市',
+ 131102: '桃城区',
+ 131121: '枣强县',
+ 131122: '武邑县',
+ 131123: '武强县',
+ 131124: '饶阳县',
+ 131125: '安平县',
+ 131126: '故城县',
+ 131127: '景县',
+ 131128: '阜城县',
+ 131181: '冀州市',
+ 131182: '深州市',
+ 131183: '其它区',
+ 140000: '山西省',
+ 140100: '太原市',
+ 140105: '小店区',
+ 140106: '迎泽区',
+ 140107: '杏花岭区',
+ 140108: '尖草坪区',
+ 140109: '万柏林区',
+ 140110: '晋源区',
+ 140121: '清徐县',
+ 140122: '阳曲县',
+ 140123: '娄烦县',
+ 140181: '古交市',
+ 140182: '其它区',
+ 140200: '大同市',
+ 140202: '城区',
+ 140203: '矿区',
+ 140211: '南郊区',
+ 140212: '新荣区',
+ 140221: '阳高县',
+ 140222: '天镇县',
+ 140223: '广灵县',
+ 140224: '灵丘县',
+ 140225: '浑源县',
+ 140226: '左云县',
+ 140227: '大同县',
+ 140228: '其它区',
+ 140300: '阳泉市',
+ 140302: '城区',
+ 140303: '矿区',
+ 140311: '郊区',
+ 140321: '平定县',
+ 140322: '盂县',
+ 140323: '其它区',
+ 140400: '长治市',
+ 140421: '长治县',
+ 140423: '襄垣县',
+ 140424: '屯留县',
+ 140425: '平顺县',
+ 140426: '黎城县',
+ 140427: '壶关县',
+ 140428: '长子县',
+ 140429: '武乡县',
+ 140430: '沁县',
+ 140431: '沁源县',
+ 140481: '潞城市',
+ 140482: '城区',
+ 140483: '郊区',
+ 140485: '其它区',
+ 140500: '晋城市',
+ 140502: '城区',
+ 140521: '沁水县',
+ 140522: '阳城县',
+ 140524: '陵川县',
+ 140525: '泽州县',
+ 140581: '高平市',
+ 140582: '其它区',
+ 140600: '朔州市',
+ 140602: '朔城区',
+ 140603: '平鲁区',
+ 140621: '山阴县',
+ 140622: '应县',
+ 140623: '右玉县',
+ 140624: '怀仁县',
+ 140625: '其它区',
+ 140700: '晋中市',
+ 140702: '榆次区',
+ 140721: '榆社县',
+ 140722: '左权县',
+ 140723: '和顺县',
+ 140724: '昔阳县',
+ 140725: '寿阳县',
+ 140726: '太谷县',
+ 140727: '祁县',
+ 140728: '平遥县',
+ 140729: '灵石县',
+ 140781: '介休市',
+ 140782: '其它区',
+ 140800: '运城市',
+ 140802: '盐湖区',
+ 140821: '临猗县',
+ 140822: '万荣县',
+ 140823: '闻喜县',
+ 140824: '稷山县',
+ 140825: '新绛县',
+ 140826: '绛县',
+ 140827: '垣曲县',
+ 140828: '夏县',
+ 140829: '平陆县',
+ 140830: '芮城县',
+ 140881: '永济市',
+ 140882: '河津市',
+ 140883: '其它区',
+ 140900: '忻州市',
+ 140902: '忻府区',
+ 140921: '定襄县',
+ 140922: '五台县',
+ 140923: '代县',
+ 140924: '繁峙县',
+ 140925: '宁武县',
+ 140926: '静乐县',
+ 140927: '神池县',
+ 140928: '五寨县',
+ 140929: '岢岚县',
+ 140930: '河曲县',
+ 140931: '保德县',
+ 140932: '偏关县',
+ 140981: '原平市',
+ 140982: '其它区',
+ 141000: '临汾市',
+ 141002: '尧都区',
+ 141021: '曲沃县',
+ 141022: '翼城县',
+ 141023: '襄汾县',
+ 141024: '洪洞县',
+ 141025: '古县',
+ 141026: '安泽县',
+ 141027: '浮山县',
+ 141028: '吉县',
+ 141029: '乡宁县',
+ 141030: '大宁县',
+ 141031: '隰县',
+ 141032: '永和县',
+ 141033: '蒲县',
+ 141034: '汾西县',
+ 141081: '侯马市',
+ 141082: '霍州市',
+ 141083: '其它区',
+ 141100: '吕梁市',
+ 141102: '离石区',
+ 141121: '文水县',
+ 141122: '交城县',
+ 141123: '兴县',
+ 141124: '临县',
+ 141125: '柳林县',
+ 141126: '石楼县',
+ 141127: '岚县',
+ 141128: '方山县',
+ 141129: '中阳县',
+ 141130: '交口县',
+ 141181: '孝义市',
+ 141182: '汾阳市',
+ 141183: '其它区',
+ 150000: '内蒙古自治区',
+ 150100: '呼和浩特市',
+ 150102: '新城区',
+ 150103: '回民区',
+ 150104: '玉泉区',
+ 150105: '赛罕区',
+ 150121: '土默特左旗',
+ 150122: '托克托县',
+ 150123: '和林格尔县',
+ 150124: '清水河县',
+ 150125: '武川县',
+ 150126: '其它区',
+ 150200: '包头市',
+ 150202: '东河区',
+ 150203: '昆都仑区',
+ 150204: '青山区',
+ 150205: '石拐区',
+ 150206: '白云鄂博矿区',
+ 150207: '九原区',
+ 150221: '土默特右旗',
+ 150222: '固阳县',
+ 150223: '达尔罕茂明安联合旗',
+ 150224: '其它区',
+ 150300: '乌海市',
+ 150302: '海勃湾区',
+ 150303: '海南区',
+ 150304: '乌达区',
+ 150305: '其它区',
+ 150400: '赤峰市',
+ 150402: '红山区',
+ 150403: '元宝山区',
+ 150404: '松山区',
+ 150421: '阿鲁科尔沁旗',
+ 150422: '巴林左旗',
+ 150423: '巴林右旗',
+ 150424: '林西县',
+ 150425: '克什克腾旗',
+ 150426: '翁牛特旗',
+ 150428: '喀喇沁旗',
+ 150429: '宁城县',
+ 150430: '敖汉旗',
+ 150431: '其它区',
+ 150500: '通辽市',
+ 150502: '科尔沁区',
+ 150521: '科尔沁左翼中旗',
+ 150522: '科尔沁左翼后旗',
+ 150523: '开鲁县',
+ 150524: '库伦旗',
+ 150525: '奈曼旗',
+ 150526: '扎鲁特旗',
+ 150581: '霍林郭勒市',
+ 150582: '其它区',
+ 150600: '鄂尔多斯市',
+ 150602: '东胜区',
+ 150621: '达拉特旗',
+ 150622: '准格尔旗',
+ 150623: '鄂托克前旗',
+ 150624: '鄂托克旗',
+ 150625: '杭锦旗',
+ 150626: '乌审旗',
+ 150627: '伊金霍洛旗',
+ 150628: '其它区',
+ 150700: '呼伦贝尔市',
+ 150702: '海拉尔区',
+ 150703: '扎赉诺尔区',
+ 150721: '阿荣旗',
+ 150722: '莫力达瓦达斡尔族自治旗',
+ 150723: '鄂伦春自治旗',
+ 150724: '鄂温克族自治旗',
+ 150725: '陈巴尔虎旗',
+ 150726: '新巴尔虎左旗',
+ 150727: '新巴尔虎右旗',
+ 150781: '满洲里市',
+ 150782: '牙克石市',
+ 150783: '扎兰屯市',
+ 150784: '额尔古纳市',
+ 150785: '根河市',
+ 150786: '其它区',
+ 150800: '巴彦淖尔市',
+ 150802: '临河区',
+ 150821: '五原县',
+ 150822: '磴口县',
+ 150823: '乌拉特前旗',
+ 150824: '乌拉特中旗',
+ 150825: '乌拉特后旗',
+ 150826: '杭锦后旗',
+ 150827: '其它区',
+ 150900: '乌兰察布市',
+ 150902: '集宁区',
+ 150921: '卓资县',
+ 150922: '化德县',
+ 150923: '商都县',
+ 150924: '兴和县',
+ 150925: '凉城县',
+ 150926: '察哈尔右翼前旗',
+ 150927: '察哈尔右翼中旗',
+ 150928: '察哈尔右翼后旗',
+ 150929: '四子王旗',
+ 150981: '丰镇市',
+ 150982: '其它区',
+ 152200: '兴安盟',
+ 152201: '乌兰浩特市',
+ 152202: '阿尔山市',
+ 152221: '科尔沁右翼前旗',
+ 152222: '科尔沁右翼中旗',
+ 152223: '扎赉特旗',
+ 152224: '突泉县',
+ 152225: '其它区',
+ 152500: '锡林郭勒盟',
+ 152501: '二连浩特市',
+ 152502: '锡林浩特市',
+ 152522: '阿巴嘎旗',
+ 152523: '苏尼特左旗',
+ 152524: '苏尼特右旗',
+ 152525: '东乌珠穆沁旗',
+ 152526: '西乌珠穆沁旗',
+ 152527: '太仆寺旗',
+ 152528: '镶黄旗',
+ 152529: '正镶白旗',
+ 152530: '正蓝旗',
+ 152531: '多伦县',
+ 152532: '其它区',
+ 152900: '阿拉善盟',
+ 152921: '阿拉善左旗',
+ 152922: '阿拉善右旗',
+ 152923: '额济纳旗',
+ 152924: '其它区',
+ 210000: '辽宁省',
+ 210100: '沈阳市',
+ 210102: '和平区',
+ 210103: '沈河区',
+ 210104: '大东区',
+ 210105: '皇姑区',
+ 210106: '铁西区',
+ 210111: '苏家屯区',
+ 210112: '东陵区',
+ 210113: '新城子区',
+ 210114: '于洪区',
+ 210122: '辽中县',
+ 210123: '康平县',
+ 210124: '法库县',
+ 210181: '新民市',
+ 210184: '沈北新区',
+ 210185: '其它区',
+ 210200: '大连市',
+ 210202: '中山区',
+ 210203: '西岗区',
+ 210204: '沙河口区',
+ 210211: '甘井子区',
+ 210212: '旅顺口区',
+ 210213: '金州区',
+ 210224: '长海县',
+ 210281: '瓦房店市',
+ 210282: '普兰店市',
+ 210283: '庄河市',
+ 210298: '其它区',
+ 210300: '鞍山市',
+ 210302: '铁东区',
+ 210303: '铁西区',
+ 210304: '立山区',
+ 210311: '千山区',
+ 210321: '台安县',
+ 210323: '岫岩满族自治县',
+ 210381: '海城市',
+ 210382: '其它区',
+ 210400: '抚顺市',
+ 210402: '新抚区',
+ 210403: '东洲区',
+ 210404: '望花区',
+ 210411: '顺城区',
+ 210421: '抚顺县',
+ 210422: '新宾满族自治县',
+ 210423: '清原满族自治县',
+ 210424: '其它区',
+ 210500: '本溪市',
+ 210502: '平山区',
+ 210503: '溪湖区',
+ 210504: '明山区',
+ 210505: '南芬区',
+ 210521: '本溪满族自治县',
+ 210522: '桓仁满族自治县',
+ 210523: '其它区',
+ 210600: '丹东市',
+ 210602: '元宝区',
+ 210603: '振兴区',
+ 210604: '振安区',
+ 210624: '宽甸满族自治县',
+ 210681: '东港市',
+ 210682: '凤城市',
+ 210683: '其它区',
+ 210700: '锦州市',
+ 210702: '古塔区',
+ 210703: '凌河区',
+ 210711: '太和区',
+ 210726: '黑山县',
+ 210727: '义县',
+ 210781: '凌海市',
+ 210782: '北镇市',
+ 210783: '其它区',
+ 210800: '营口市',
+ 210802: '站前区',
+ 210803: '西市区',
+ 210804: '鲅鱼圈区',
+ 210811: '老边区',
+ 210881: '盖州市',
+ 210882: '大石桥市',
+ 210883: '其它区',
+ 210900: '阜新市',
+ 210902: '海州区',
+ 210903: '新邱区',
+ 210904: '太平区',
+ 210905: '清河门区',
+ 210911: '细河区',
+ 210921: '阜新蒙古族自治县',
+ 210922: '彰武县',
+ 210923: '其它区',
+ 211000: '辽阳市',
+ 211002: '白塔区',
+ 211003: '文圣区',
+ 211004: '宏伟区',
+ 211005: '弓长岭区',
+ 211011: '太子河区',
+ 211021: '辽阳县',
+ 211081: '灯塔市',
+ 211082: '其它区',
+ 211100: '盘锦市',
+ 211102: '双台子区',
+ 211103: '兴隆台区',
+ 211121: '大洼县',
+ 211122: '盘山县',
+ 211123: '其它区',
+ 211200: '铁岭市',
+ 211202: '银州区',
+ 211204: '清河区',
+ 211221: '铁岭县',
+ 211223: '西丰县',
+ 211224: '昌图县',
+ 211281: '调兵山市',
+ 211282: '开原市',
+ 211283: '其它区',
+ 211300: '朝阳市',
+ 211302: '双塔区',
+ 211303: '龙城区',
+ 211321: '朝阳县',
+ 211322: '建平县',
+ 211324: '喀喇沁左翼蒙古族自治县',
+ 211381: '北票市',
+ 211382: '凌源市',
+ 211383: '其它区',
+ 211400: '葫芦岛市',
+ 211402: '连山区',
+ 211403: '龙港区',
+ 211404: '南票区',
+ 211421: '绥中县',
+ 211422: '建昌县',
+ 211481: '兴城市',
+ 211482: '其它区',
+ 220000: '吉林省',
+ 220100: '长春市',
+ 220102: '南关区',
+ 220103: '宽城区',
+ 220104: '朝阳区',
+ 220105: '二道区',
+ 220106: '绿园区',
+ 220112: '双阳区',
+ 220122: '农安县',
+ 220181: '九台市',
+ 220182: '榆树市',
+ 220183: '德惠市',
+ 220188: '其它区',
+ 220200: '吉林市',
+ 220202: '昌邑区',
+ 220203: '龙潭区',
+ 220204: '船营区',
+ 220211: '丰满区',
+ 220221: '永吉县',
+ 220281: '蛟河市',
+ 220282: '桦甸市',
+ 220283: '舒兰市',
+ 220284: '磐石市',
+ 220285: '其它区',
+ 220300: '四平市',
+ 220302: '铁西区',
+ 220303: '铁东区',
+ 220322: '梨树县',
+ 220323: '伊通满族自治县',
+ 220381: '公主岭市',
+ 220382: '双辽市',
+ 220383: '其它区',
+ 220400: '辽源市',
+ 220402: '龙山区',
+ 220403: '西安区',
+ 220421: '东丰县',
+ 220422: '东辽县',
+ 220423: '其它区',
+ 220500: '通化市',
+ 220502: '东昌区',
+ 220503: '二道江区',
+ 220521: '通化县',
+ 220523: '辉南县',
+ 220524: '柳河县',
+ 220581: '梅河口市',
+ 220582: '集安市',
+ 220583: '其它区',
+ 220600: '白山市',
+ 220602: '浑江区',
+ 220621: '抚松县',
+ 220622: '靖宇县',
+ 220623: '长白朝鲜族自治县',
+ 220625: '江源区',
+ 220681: '临江市',
+ 220682: '其它区',
+ 220700: '松原市',
+ 220702: '宁江区',
+ 220721: '前郭尔罗斯蒙古族自治县',
+ 220722: '长岭县',
+ 220723: '乾安县',
+ 220724: '扶余市',
+ 220725: '其它区',
+ 220800: '白城市',
+ 220802: '洮北区',
+ 220821: '镇赉县',
+ 220822: '通榆县',
+ 220881: '洮南市',
+ 220882: '大安市',
+ 220883: '其它区',
+ 222400: '延边朝鲜族自治州',
+ 222401: '延吉市',
+ 222402: '图们市',
+ 222403: '敦化市',
+ 222404: '珲春市',
+ 222405: '龙井市',
+ 222406: '和龙市',
+ 222424: '汪清县',
+ 222426: '安图县',
+ 222427: '其它区',
+ 230000: '黑龙江省',
+ 230100: '哈尔滨市',
+ 230102: '道里区',
+ 230103: '南岗区',
+ 230104: '道外区',
+ 230106: '香坊区',
+ 230108: '平房区',
+ 230109: '松北区',
+ 230111: '呼兰区',
+ 230123: '依兰县',
+ 230124: '方正县',
+ 230125: '宾县',
+ 230126: '巴彦县',
+ 230127: '木兰县',
+ 230128: '通河县',
+ 230129: '延寿县',
+ 230181: '阿城区',
+ 230182: '双城市',
+ 230183: '尚志市',
+ 230184: '五常市',
+ 230186: '其它区',
+ 230200: '齐齐哈尔市',
+ 230202: '龙沙区',
+ 230203: '建华区',
+ 230204: '铁锋区',
+ 230205: '昂昂溪区',
+ 230206: '富拉尔基区',
+ 230207: '碾子山区',
+ 230208: '梅里斯达斡尔族区',
+ 230221: '龙江县',
+ 230223: '依安县',
+ 230224: '泰来县',
+ 230225: '甘南县',
+ 230227: '富裕县',
+ 230229: '克山县',
+ 230230: '克东县',
+ 230231: '拜泉县',
+ 230281: '讷河市',
+ 230282: '其它区',
+ 230300: '鸡西市',
+ 230302: '鸡冠区',
+ 230303: '恒山区',
+ 230304: '滴道区',
+ 230305: '梨树区',
+ 230306: '城子河区',
+ 230307: '麻山区',
+ 230321: '鸡东县',
+ 230381: '虎林市',
+ 230382: '密山市',
+ 230383: '其它区',
+ 230400: '鹤岗市',
+ 230402: '向阳区',
+ 230403: '工农区',
+ 230404: '南山区',
+ 230405: '兴安区',
+ 230406: '东山区',
+ 230407: '兴山区',
+ 230421: '萝北县',
+ 230422: '绥滨县',
+ 230423: '其它区',
+ 230500: '双鸭山市',
+ 230502: '尖山区',
+ 230503: '岭东区',
+ 230505: '四方台区',
+ 230506: '宝山区',
+ 230521: '集贤县',
+ 230522: '友谊县',
+ 230523: '宝清县',
+ 230524: '饶河县',
+ 230525: '其它区',
+ 230600: '大庆市',
+ 230602: '萨尔图区',
+ 230603: '龙凤区',
+ 230604: '让胡路区',
+ 230605: '红岗区',
+ 230606: '大同区',
+ 230621: '肇州县',
+ 230622: '肇源县',
+ 230623: '林甸县',
+ 230624: '杜尔伯特蒙古族自治县',
+ 230625: '其它区',
+ 230700: '伊春市',
+ 230702: '伊春区',
+ 230703: '南岔区',
+ 230704: '友好区',
+ 230705: '西林区',
+ 230706: '翠峦区',
+ 230707: '新青区',
+ 230708: '美溪区',
+ 230709: '金山屯区',
+ 230710: '五营区',
+ 230711: '乌马河区',
+ 230712: '汤旺河区',
+ 230713: '带岭区',
+ 230714: '乌伊岭区',
+ 230715: '红星区',
+ 230716: '上甘岭区',
+ 230722: '嘉荫县',
+ 230781: '铁力市',
+ 230782: '其它区',
+ 230800: '佳木斯市',
+ 230803: '向阳区',
+ 230804: '前进区',
+ 230805: '东风区',
+ 230811: '郊区',
+ 230822: '桦南县',
+ 230826: '桦川县',
+ 230828: '汤原县',
+ 230833: '抚远县',
+ 230881: '同江市',
+ 230882: '富锦市',
+ 230883: '其它区',
+ 230900: '七台河市',
+ 230902: '新兴区',
+ 230903: '桃山区',
+ 230904: '茄子河区',
+ 230921: '勃利县',
+ 230922: '其它区',
+ 231000: '牡丹江市',
+ 231002: '东安区',
+ 231003: '阳明区',
+ 231004: '爱民区',
+ 231005: '西安区',
+ 231024: '东宁县',
+ 231025: '林口县',
+ 231081: '绥芬河市',
+ 231083: '海林市',
+ 231084: '宁安市',
+ 231085: '穆棱市',
+ 231086: '其它区',
+ 231100: '黑河市',
+ 231102: '爱辉区',
+ 231121: '嫩江县',
+ 231123: '逊克县',
+ 231124: '孙吴县',
+ 231181: '北安市',
+ 231182: '五大连池市',
+ 231183: '其它区',
+ 231200: '绥化市',
+ 231202: '北林区',
+ 231221: '望奎县',
+ 231222: '兰西县',
+ 231223: '青冈县',
+ 231224: '庆安县',
+ 231225: '明水县',
+ 231226: '绥棱县',
+ 231281: '安达市',
+ 231282: '肇东市',
+ 231283: '海伦市',
+ 231284: '其它区',
+ 232700: '大兴安岭地区',
+ 232702: '松岭区',
+ 232703: '新林区',
+ 232704: '呼中区',
+ 232721: '呼玛县',
+ 232722: '塔河县',
+ 232723: '漠河县',
+ 232724: '加格达奇区',
+ 232725: '其它区',
+ 310000: '上海',
+ 310100: '上海市',
+ 310101: '黄浦区',
+ 310104: '徐汇区',
+ 310105: '长宁区',
+ 310106: '静安区',
+ 310107: '普陀区',
+ 310108: '闸北区',
+ 310109: '虹口区',
+ 310110: '杨浦区',
+ 310112: '闵行区',
+ 310113: '宝山区',
+ 310114: '嘉定区',
+ 310115: '浦东新区',
+ 310116: '金山区',
+ 310117: '松江区',
+ 310118: '青浦区',
+ 310120: '奉贤区',
+ 310230: '崇明县',
+ 310231: '其它区',
+ 320000: '江苏省',
+ 320100: '南京市',
+ 320102: '玄武区',
+ 320104: '秦淮区',
+ 320105: '建邺区',
+ 320106: '鼓楼区',
+ 320111: '浦口区',
+ 320113: '栖霞区',
+ 320114: '雨花台区',
+ 320115: '江宁区',
+ 320116: '六合区',
+ 320124: '溧水区',
+ 320125: '高淳区',
+ 320126: '其它区',
+ 320200: '无锡市',
+ 320202: '崇安区',
+ 320203: '南长区',
+ 320204: '北塘区',
+ 320205: '锡山区',
+ 320206: '惠山区',
+ 320211: '滨湖区',
+ 320281: '江阴市',
+ 320282: '宜兴市',
+ 320297: '其它区',
+ 320300: '徐州市',
+ 320302: '鼓楼区',
+ 320303: '云龙区',
+ 320305: '贾汪区',
+ 320311: '泉山区',
+ 320321: '丰县',
+ 320322: '沛县',
+ 320323: '铜山区',
+ 320324: '睢宁县',
+ 320381: '新沂市',
+ 320382: '邳州市',
+ 320383: '其它区',
+ 320400: '常州市',
+ 320402: '天宁区',
+ 320404: '钟楼区',
+ 320405: '戚墅堰区',
+ 320411: '新北区',
+ 320412: '武进区',
+ 320481: '溧阳市',
+ 320482: '金坛市',
+ 320483: '其它区',
+ 320500: '苏州市',
+ 320505: '虎丘区',
+ 320506: '吴中区',
+ 320507: '相城区',
+ 320508: '姑苏区',
+ 320581: '常熟市',
+ 320582: '张家港市',
+ 320583: '昆山市',
+ 320584: '吴江区',
+ 320585: '太仓市',
+ 320596: '其它区',
+ 320600: '南通市',
+ 320602: '崇川区',
+ 320611: '港闸区',
+ 320612: '通州区',
+ 320621: '海安县',
+ 320623: '如东县',
+ 320681: '启东市',
+ 320682: '如皋市',
+ 320684: '海门市',
+ 320694: '其它区',
+ 320700: '连云港市',
+ 320703: '连云区',
+ 320705: '新浦区',
+ 320706: '海州区',
+ 320721: '赣榆县',
+ 320722: '东海县',
+ 320723: '灌云县',
+ 320724: '灌南县',
+ 320725: '其它区',
+ 320800: '淮安市',
+ 320802: '清河区',
+ 320803: '淮安区',
+ 320804: '淮阴区',
+ 320811: '清浦区',
+ 320826: '涟水县',
+ 320829: '洪泽县',
+ 320830: '盱眙县',
+ 320831: '金湖县',
+ 320832: '其它区',
+ 320900: '盐城市',
+ 320902: '亭湖区',
+ 320903: '盐都区',
+ 320921: '响水县',
+ 320922: '滨海县',
+ 320923: '阜宁县',
+ 320924: '射阳县',
+ 320925: '建湖县',
+ 320981: '东台市',
+ 320982: '大丰市',
+ 320983: '其它区',
+ 321000: '扬州市',
+ 321002: '广陵区',
+ 321003: '邗江区',
+ 321023: '宝应县',
+ 321081: '仪征市',
+ 321084: '高邮市',
+ 321088: '江都区',
+ 321093: '其它区',
+ 321100: '镇江市',
+ 321102: '京口区',
+ 321111: '润州区',
+ 321112: '丹徒区',
+ 321181: '丹阳市',
+ 321182: '扬中市',
+ 321183: '句容市',
+ 321184: '其它区',
+ 321200: '泰州市',
+ 321202: '海陵区',
+ 321203: '高港区',
+ 321281: '兴化市',
+ 321282: '靖江市',
+ 321283: '泰兴市',
+ 321284: '姜堰区',
+ 321285: '其它区',
+ 321300: '宿迁市',
+ 321302: '宿城区',
+ 321311: '宿豫区',
+ 321322: '沭阳县',
+ 321323: '泗阳县',
+ 321324: '泗洪县',
+ 321325: '其它区',
+ 330000: '浙江省',
+ 330100: '杭州市',
+ 330102: '上城区',
+ 330103: '下城区',
+ 330104: '江干区',
+ 330105: '拱墅区',
+ 330106: '西湖区',
+ 330108: '滨江区',
+ 330109: '萧山区',
+ 330110: '余杭区',
+ 330122: '桐庐县',
+ 330127: '淳安县',
+ 330182: '建德市',
+ 330183: '富阳市',
+ 330185: '临安市',
+ 330186: '其它区',
+ 330200: '宁波市',
+ 330203: '海曙区',
+ 330204: '江东区',
+ 330205: '江北区',
+ 330206: '北仑区',
+ 330211: '镇海区',
+ 330212: '鄞州区',
+ 330225: '象山县',
+ 330226: '宁海县',
+ 330281: '余姚市',
+ 330282: '慈溪市',
+ 330283: '奉化市',
+ 330284: '其它区',
+ 330300: '温州市',
+ 330302: '鹿城区',
+ 330303: '龙湾区',
+ 330304: '瓯海区',
+ 330322: '洞头县',
+ 330324: '永嘉县',
+ 330326: '平阳县',
+ 330327: '苍南县',
+ 330328: '文成县',
+ 330329: '泰顺县',
+ 330381: '瑞安市',
+ 330382: '乐清市',
+ 330383: '其它区',
+ 330400: '嘉兴市',
+ 330402: '南湖区',
+ 330411: '秀洲区',
+ 330421: '嘉善县',
+ 330424: '海盐县',
+ 330481: '海宁市',
+ 330482: '平湖市',
+ 330483: '桐乡市',
+ 330484: '其它区',
+ 330500: '湖州市',
+ 330502: '吴兴区',
+ 330503: '南浔区',
+ 330521: '德清县',
+ 330522: '长兴县',
+ 330523: '安吉县',
+ 330524: '其它区',
+ 330600: '绍兴市',
+ 330602: '越城区',
+ 330621: '绍兴县',
+ 330624: '新昌县',
+ 330681: '诸暨市',
+ 330682: '上虞市',
+ 330683: '嵊州市',
+ 330684: '其它区',
+ 330700: '金华市',
+ 330702: '婺城区',
+ 330703: '金东区',
+ 330723: '武义县',
+ 330726: '浦江县',
+ 330727: '磐安县',
+ 330781: '兰溪市',
+ 330782: '义乌市',
+ 330783: '东阳市',
+ 330784: '永康市',
+ 330785: '其它区',
+ 330800: '衢州市',
+ 330802: '柯城区',
+ 330803: '衢江区',
+ 330822: '常山县',
+ 330824: '开化县',
+ 330825: '龙游县',
+ 330881: '江山市',
+ 330882: '其它区',
+ 330900: '舟山市',
+ 330902: '定海区',
+ 330903: '普陀区',
+ 330921: '岱山县',
+ 330922: '嵊泗县',
+ 330923: '其它区',
+ 331000: '台州市',
+ 331002: '椒江区',
+ 331003: '黄岩区',
+ 331004: '路桥区',
+ 331021: '玉环县',
+ 331022: '三门县',
+ 331023: '天台县',
+ 331024: '仙居县',
+ 331081: '温岭市',
+ 331082: '临海市',
+ 331083: '其它区',
+ 331100: '丽水市',
+ 331102: '莲都区',
+ 331121: '青田县',
+ 331122: '缙云县',
+ 331123: '遂昌县',
+ 331124: '松阳县',
+ 331125: '云和县',
+ 331126: '庆元县',
+ 331127: '景宁畲族自治县',
+ 331181: '龙泉市',
+ 331182: '其它区',
+ 340000: '安徽省',
+ 340100: '合肥市',
+ 340102: '瑶海区',
+ 340103: '庐阳区',
+ 340104: '蜀山区',
+ 340111: '包河区',
+ 340121: '长丰县',
+ 340122: '肥东县',
+ 340123: '肥西县',
+ 340192: '其它区',
+ 340200: '芜湖市',
+ 340202: '镜湖区',
+ 340203: '弋江区',
+ 340207: '鸠江区',
+ 340208: '三山区',
+ 340221: '芜湖县',
+ 340222: '繁昌县',
+ 340223: '南陵县',
+ 340224: '其它区',
+ 340300: '蚌埠市',
+ 340302: '龙子湖区',
+ 340303: '蚌山区',
+ 340304: '禹会区',
+ 340311: '淮上区',
+ 340321: '怀远县',
+ 340322: '五河县',
+ 340323: '固镇县',
+ 340324: '其它区',
+ 340400: '淮南市',
+ 340402: '大通区',
+ 340403: '田家庵区',
+ 340404: '谢家集区',
+ 340405: '八公山区',
+ 340406: '潘集区',
+ 340421: '凤台县',
+ 340422: '其它区',
+ 340500: '马鞍山市',
+ 340503: '花山区',
+ 340504: '雨山区',
+ 340506: '博望区',
+ 340521: '当涂县',
+ 340522: '其它区',
+ 340600: '淮北市',
+ 340602: '杜集区',
+ 340603: '相山区',
+ 340604: '烈山区',
+ 340621: '濉溪县',
+ 340622: '其它区',
+ 340700: '铜陵市',
+ 340702: '铜官山区',
+ 340703: '狮子山区',
+ 340711: '郊区',
+ 340721: '铜陵县',
+ 340722: '其它区',
+ 340800: '安庆市',
+ 340802: '迎江区',
+ 340803: '大观区',
+ 340811: '宜秀区',
+ 340822: '怀宁县',
+ 340823: '枞阳县',
+ 340824: '潜山县',
+ 340825: '太湖县',
+ 340826: '宿松县',
+ 340827: '望江县',
+ 340828: '岳西县',
+ 340881: '桐城市',
+ 340882: '其它区',
+ 341000: '黄山市',
+ 341002: '屯溪区',
+ 341003: '黄山区',
+ 341004: '徽州区',
+ 341021: '歙县',
+ 341022: '休宁县',
+ 341023: '黟县',
+ 341024: '祁门县',
+ 341025: '其它区',
+ 341100: '滁州市',
+ 341102: '琅琊区',
+ 341103: '南谯区',
+ 341122: '来安县',
+ 341124: '全椒县',
+ 341125: '定远县',
+ 341126: '凤阳县',
+ 341181: '天长市',
+ 341182: '明光市',
+ 341183: '其它区',
+ 341200: '阜阳市',
+ 341202: '颍州区',
+ 341203: '颍东区',
+ 341204: '颍泉区',
+ 341221: '临泉县',
+ 341222: '太和县',
+ 341225: '阜南县',
+ 341226: '颍上县',
+ 341282: '界首市',
+ 341283: '其它区',
+ 341300: '宿州市',
+ 341302: '埇桥区',
+ 341321: '砀山县',
+ 341322: '萧县',
+ 341323: '灵璧县',
+ 341324: '泗县',
+ 341325: '其它区',
+ 341400: '巢湖市',
+ 341421: '庐江县',
+ 341422: '无为县',
+ 341423: '含山县',
+ 341424: '和县',
+ 341500: '六安市',
+ 341502: '金安区',
+ 341503: '裕安区',
+ 341521: '寿县',
+ 341522: '霍邱县',
+ 341523: '舒城县',
+ 341524: '金寨县',
+ 341525: '霍山县',
+ 341526: '其它区',
+ 341600: '亳州市',
+ 341602: '谯城区',
+ 341621: '涡阳县',
+ 341622: '蒙城县',
+ 341623: '利辛县',
+ 341624: '其它区',
+ 341700: '池州市',
+ 341702: '贵池区',
+ 341721: '东至县',
+ 341722: '石台县',
+ 341723: '青阳县',
+ 341724: '其它区',
+ 341800: '宣城市',
+ 341802: '宣州区',
+ 341821: '郎溪县',
+ 341822: '广德县',
+ 341823: '泾县',
+ 341824: '绩溪县',
+ 341825: '旌德县',
+ 341881: '宁国市',
+ 341882: '其它区',
+ 350000: '福建省',
+ 350100: '福州市',
+ 350102: '鼓楼区',
+ 350103: '台江区',
+ 350104: '仓山区',
+ 350105: '马尾区',
+ 350111: '晋安区',
+ 350121: '闽侯县',
+ 350122: '连江县',
+ 350123: '罗源县',
+ 350124: '闽清县',
+ 350125: '永泰县',
+ 350128: '平潭县',
+ 350181: '福清市',
+ 350182: '长乐市',
+ 350183: '其它区',
+ 350200: '厦门市',
+ 350203: '思明区',
+ 350205: '海沧区',
+ 350206: '湖里区',
+ 350211: '集美区',
+ 350212: '同安区',
+ 350213: '翔安区',
+ 350214: '其它区',
+ 350300: '莆田市',
+ 350302: '城厢区',
+ 350303: '涵江区',
+ 350304: '荔城区',
+ 350305: '秀屿区',
+ 350322: '仙游县',
+ 350323: '其它区',
+ 350400: '三明市',
+ 350402: '梅列区',
+ 350403: '三元区',
+ 350421: '明溪县',
+ 350423: '清流县',
+ 350424: '宁化县',
+ 350425: '大田县',
+ 350426: '尤溪县',
+ 350427: '沙县',
+ 350428: '将乐县',
+ 350429: '泰宁县',
+ 350430: '建宁县',
+ 350481: '永安市',
+ 350482: '其它区',
+ 350500: '泉州市',
+ 350502: '鲤城区',
+ 350503: '丰泽区',
+ 350504: '洛江区',
+ 350505: '泉港区',
+ 350521: '惠安县',
+ 350524: '安溪县',
+ 350525: '永春县',
+ 350526: '德化县',
+ 350527: '金门县',
+ 350581: '石狮市',
+ 350582: '晋江市',
+ 350583: '南安市',
+ 350584: '其它区',
+ 350600: '漳州市',
+ 350602: '芗城区',
+ 350603: '龙文区',
+ 350622: '云霄县',
+ 350623: '漳浦县',
+ 350624: '诏安县',
+ 350625: '长泰县',
+ 350626: '东山县',
+ 350627: '南靖县',
+ 350628: '平和县',
+ 350629: '华安县',
+ 350681: '龙海市',
+ 350682: '其它区',
+ 350700: '南平市',
+ 350702: '延平区',
+ 350721: '顺昌县',
+ 350722: '浦城县',
+ 350723: '光泽县',
+ 350724: '松溪县',
+ 350725: '政和县',
+ 350781: '邵武市',
+ 350782: '武夷山市',
+ 350783: '建瓯市',
+ 350784: '建阳市',
+ 350785: '其它区',
+ 350800: '龙岩市',
+ 350802: '新罗区',
+ 350821: '长汀县',
+ 350822: '永定县',
+ 350823: '上杭县',
+ 350824: '武平县',
+ 350825: '连城县',
+ 350881: '漳平市',
+ 350882: '其它区',
+ 350900: '宁德市',
+ 350902: '蕉城区',
+ 350921: '霞浦县',
+ 350922: '古田县',
+ 350923: '屏南县',
+ 350924: '寿宁县',
+ 350925: '周宁县',
+ 350926: '柘荣县',
+ 350981: '福安市',
+ 350982: '福鼎市',
+ 350983: '其它区',
+ 360000: '江西省',
+ 360100: '南昌市',
+ 360102: '东湖区',
+ 360103: '西湖区',
+ 360104: '青云谱区',
+ 360105: '湾里区',
+ 360111: '青山湖区',
+ 360121: '南昌县',
+ 360122: '新建县',
+ 360123: '安义县',
+ 360124: '进贤县',
+ 360128: '其它区',
+ 360200: '景德镇市',
+ 360202: '昌江区',
+ 360203: '珠山区',
+ 360222: '浮梁县',
+ 360281: '乐平市',
+ 360282: '其它区',
+ 360300: '萍乡市',
+ 360302: '安源区',
+ 360313: '湘东区',
+ 360321: '莲花县',
+ 360322: '上栗县',
+ 360323: '芦溪县',
+ 360324: '其它区',
+ 360400: '九江市',
+ 360402: '庐山区',
+ 360403: '浔阳区',
+ 360421: '九江县',
+ 360423: '武宁县',
+ 360424: '修水县',
+ 360425: '永修县',
+ 360426: '德安县',
+ 360427: '星子县',
+ 360428: '都昌县',
+ 360429: '湖口县',
+ 360430: '彭泽县',
+ 360481: '瑞昌市',
+ 360482: '其它区',
+ 360483: '共青城市',
+ 360500: '新余市',
+ 360502: '渝水区',
+ 360521: '分宜县',
+ 360522: '其它区',
+ 360600: '鹰潭市',
+ 360602: '月湖区',
+ 360622: '余江县',
+ 360681: '贵溪市',
+ 360682: '其它区',
+ 360700: '赣州市',
+ 360702: '章贡区',
+ 360721: '赣县',
+ 360722: '信丰县',
+ 360723: '大余县',
+ 360724: '上犹县',
+ 360725: '崇义县',
+ 360726: '安远县',
+ 360727: '龙南县',
+ 360728: '定南县',
+ 360729: '全南县',
+ 360730: '宁都县',
+ 360731: '于都县',
+ 360732: '兴国县',
+ 360733: '会昌县',
+ 360734: '寻乌县',
+ 360735: '石城县',
+ 360781: '瑞金市',
+ 360782: '南康市',
+ 360783: '其它区',
+ 360800: '吉安市',
+ 360802: '吉州区',
+ 360803: '青原区',
+ 360821: '吉安县',
+ 360822: '吉水县',
+ 360823: '峡江县',
+ 360824: '新干县',
+ 360825: '永丰县',
+ 360826: '泰和县',
+ 360827: '遂川县',
+ 360828: '万安县',
+ 360829: '安福县',
+ 360830: '永新县',
+ 360881: '井冈山市',
+ 360882: '其它区',
+ 360900: '宜春市',
+ 360902: '袁州区',
+ 360921: '奉新县',
+ 360922: '万载县',
+ 360923: '上高县',
+ 360924: '宜丰县',
+ 360925: '靖安县',
+ 360926: '铜鼓县',
+ 360981: '丰城市',
+ 360982: '樟树市',
+ 360983: '高安市',
+ 360984: '其它区',
+ 361000: '抚州市',
+ 361002: '临川区',
+ 361021: '南城县',
+ 361022: '黎川县',
+ 361023: '南丰县',
+ 361024: '崇仁县',
+ 361025: '乐安县',
+ 361026: '宜黄县',
+ 361027: '金溪县',
+ 361028: '资溪县',
+ 361029: '东乡县',
+ 361030: '广昌县',
+ 361031: '其它区',
+ 361100: '上饶市',
+ 361102: '信州区',
+ 361121: '上饶县',
+ 361122: '广丰县',
+ 361123: '玉山县',
+ 361124: '铅山县',
+ 361125: '横峰县',
+ 361126: '弋阳县',
+ 361127: '余干县',
+ 361128: '鄱阳县',
+ 361129: '万年县',
+ 361130: '婺源县',
+ 361181: '德兴市',
+ 361182: '其它区',
+ 370000: '山东省',
+ 370100: '济南市',
+ 370102: '历下区',
+ 370103: '市中区',
+ 370104: '槐荫区',
+ 370105: '天桥区',
+ 370112: '历城区',
+ 370113: '长清区',
+ 370124: '平阴县',
+ 370125: '济阳县',
+ 370126: '商河县',
+ 370181: '章丘市',
+ 370182: '其它区',
+ 370200: '青岛市',
+ 370202: '市南区',
+ 370203: '市北区',
+ 370211: '黄岛区',
+ 370212: '崂山区',
+ 370213: '李沧区',
+ 370214: '城阳区',
+ 370281: '胶州市',
+ 370282: '即墨市',
+ 370283: '平度市',
+ 370285: '莱西市',
+ 370286: '其它区',
+ 370300: '淄博市',
+ 370302: '淄川区',
+ 370303: '张店区',
+ 370304: '博山区',
+ 370305: '临淄区',
+ 370306: '周村区',
+ 370321: '桓台县',
+ 370322: '高青县',
+ 370323: '沂源县',
+ 370324: '其它区',
+ 370400: '枣庄市',
+ 370402: '市中区',
+ 370403: '薛城区',
+ 370404: '峄城区',
+ 370405: '台儿庄区',
+ 370406: '山亭区',
+ 370481: '滕州市',
+ 370482: '其它区',
+ 370500: '东营市',
+ 370502: '东营区',
+ 370503: '河口区',
+ 370521: '垦利县',
+ 370522: '利津县',
+ 370523: '广饶县',
+ 370591: '其它区',
+ 370600: '烟台市',
+ 370602: '芝罘区',
+ 370611: '福山区',
+ 370612: '牟平区',
+ 370613: '莱山区',
+ 370634: '长岛县',
+ 370681: '龙口市',
+ 370682: '莱阳市',
+ 370683: '莱州市',
+ 370684: '蓬莱市',
+ 370685: '招远市',
+ 370686: '栖霞市',
+ 370687: '海阳市',
+ 370688: '其它区',
+ 370700: '潍坊市',
+ 370702: '潍城区',
+ 370703: '寒亭区',
+ 370704: '坊子区',
+ 370705: '奎文区',
+ 370724: '临朐县',
+ 370725: '昌乐县',
+ 370781: '青州市',
+ 370782: '诸城市',
+ 370783: '寿光市',
+ 370784: '安丘市',
+ 370785: '高密市',
+ 370786: '昌邑市',
+ 370787: '其它区',
+ 370800: '济宁市',
+ 370802: '市中区',
+ 370811: '任城区',
+ 370826: '微山县',
+ 370827: '鱼台县',
+ 370828: '金乡县',
+ 370829: '嘉祥县',
+ 370830: '汶上县',
+ 370831: '泗水县',
+ 370832: '梁山县',
+ 370881: '曲阜市',
+ 370882: '兖州市',
+ 370883: '邹城市',
+ 370884: '其它区',
+ 370900: '泰安市',
+ 370902: '泰山区',
+ 370903: '岱岳区',
+ 370921: '宁阳县',
+ 370923: '东平县',
+ 370982: '新泰市',
+ 370983: '肥城市',
+ 370984: '其它区',
+ 371000: '威海市',
+ 371002: '环翠区',
+ 371081: '文登市',
+ 371082: '荣成市',
+ 371083: '乳山市',
+ 371084: '其它区',
+ 371100: '日照市',
+ 371102: '东港区',
+ 371103: '岚山区',
+ 371121: '五莲县',
+ 371122: '莒县',
+ 371123: '其它区',
+ 371200: '莱芜市',
+ 371202: '莱城区',
+ 371203: '钢城区',
+ 371204: '其它区',
+ 371300: '临沂市',
+ 371302: '兰山区',
+ 371311: '罗庄区',
+ 371312: '河东区',
+ 371321: '沂南县',
+ 371322: '郯城县',
+ 371323: '沂水县',
+ 371324: '苍山县',
+ 371325: '费县',
+ 371326: '平邑县',
+ 371327: '莒南县',
+ 371328: '蒙阴县',
+ 371329: '临沭县',
+ 371330: '其它区',
+ 371400: '德州市',
+ 371402: '德城区',
+ 371421: '陵县',
+ 371422: '宁津县',
+ 371423: '庆云县',
+ 371424: '临邑县',
+ 371425: '齐河县',
+ 371426: '平原县',
+ 371427: '夏津县',
+ 371428: '武城县',
+ 371481: '乐陵市',
+ 371482: '禹城市',
+ 371483: '其它区',
+ 371500: '聊城市',
+ 371502: '东昌府区',
+ 371521: '阳谷县',
+ 371522: '莘县',
+ 371523: '茌平县',
+ 371524: '东阿县',
+ 371525: '冠县',
+ 371526: '高唐县',
+ 371581: '临清市',
+ 371582: '其它区',
+ 371600: '滨州市',
+ 371602: '滨城区',
+ 371621: '惠民县',
+ 371622: '阳信县',
+ 371623: '无棣县',
+ 371624: '沾化县',
+ 371625: '博兴县',
+ 371626: '邹平县',
+ 371627: '其它区',
+ 371700: '菏泽市',
+ 371702: '牡丹区',
+ 371721: '曹县',
+ 371722: '单县',
+ 371723: '成武县',
+ 371724: '巨野县',
+ 371725: '郓城县',
+ 371726: '鄄城县',
+ 371727: '定陶县',
+ 371728: '东明县',
+ 371729: '其它区',
+ 410000: '河南省',
+ 410100: '郑州市',
+ 410102: '中原区',
+ 410103: '二七区',
+ 410104: '管城回族区',
+ 410105: '金水区',
+ 410106: '上街区',
+ 410108: '惠济区',
+ 410122: '中牟县',
+ 410181: '巩义市',
+ 410182: '荥阳市',
+ 410183: '新密市',
+ 410184: '新郑市',
+ 410185: '登封市',
+ 410188: '其它区',
+ 410200: '开封市',
+ 410202: '龙亭区',
+ 410203: '顺河回族区',
+ 410204: '鼓楼区',
+ 410205: '禹王台区',
+ 410211: '金明区',
+ 410221: '杞县',
+ 410222: '通许县',
+ 410223: '尉氏县',
+ 410224: '开封县',
+ 410225: '兰考县',
+ 410226: '其它区',
+ 410300: '洛阳市',
+ 410302: '老城区',
+ 410303: '西工区',
+ 410304: '瀍河回族区',
+ 410305: '涧西区',
+ 410306: '吉利区',
+ 410307: '洛龙区',
+ 410322: '孟津县',
+ 410323: '新安县',
+ 410324: '栾川县',
+ 410325: '嵩县',
+ 410326: '汝阳县',
+ 410327: '宜阳县',
+ 410328: '洛宁县',
+ 410329: '伊川县',
+ 410381: '偃师市',
+ 410400: '平顶山市',
+ 410402: '新华区',
+ 410403: '卫东区',
+ 410404: '石龙区',
+ 410411: '湛河区',
+ 410421: '宝丰县',
+ 410422: '叶县',
+ 410423: '鲁山县',
+ 410425: '郏县',
+ 410481: '舞钢市',
+ 410482: '汝州市',
+ 410483: '其它区',
+ 410500: '安阳市',
+ 410502: '文峰区',
+ 410503: '北关区',
+ 410505: '殷都区',
+ 410506: '龙安区',
+ 410522: '安阳县',
+ 410523: '汤阴县',
+ 410526: '滑县',
+ 410527: '内黄县',
+ 410581: '林州市',
+ 410582: '其它区',
+ 410600: '鹤壁市',
+ 410602: '鹤山区',
+ 410603: '山城区',
+ 410611: '淇滨区',
+ 410621: '浚县',
+ 410622: '淇县',
+ 410623: '其它区',
+ 410700: '新乡市',
+ 410702: '红旗区',
+ 410703: '卫滨区',
+ 410704: '凤泉区',
+ 410711: '牧野区',
+ 410721: '新乡县',
+ 410724: '获嘉县',
+ 410725: '原阳县',
+ 410726: '延津县',
+ 410727: '封丘县',
+ 410728: '长垣县',
+ 410781: '卫辉市',
+ 410782: '辉县市',
+ 410783: '其它区',
+ 410800: '焦作市',
+ 410802: '解放区',
+ 410803: '中站区',
+ 410804: '马村区',
+ 410811: '山阳区',
+ 410821: '修武县',
+ 410822: '博爱县',
+ 410823: '武陟县',
+ 410825: '温县',
+ 410881: '济源市',
+ 410882: '沁阳市',
+ 410883: '孟州市',
+ 410884: '其它区',
+ 410900: '濮阳市',
+ 410902: '华龙区',
+ 410922: '清丰县',
+ 410923: '南乐县',
+ 410926: '范县',
+ 410927: '台前县',
+ 410928: '濮阳县',
+ 410929: '其它区',
+ 411000: '许昌市',
+ 411002: '魏都区',
+ 411023: '许昌县',
+ 411024: '鄢陵县',
+ 411025: '襄城县',
+ 411081: '禹州市',
+ 411082: '长葛市',
+ 411083: '其它区',
+ 411100: '漯河市',
+ 411102: '源汇区',
+ 411103: '郾城区',
+ 411104: '召陵区',
+ 411121: '舞阳县',
+ 411122: '临颍县',
+ 411123: '其它区',
+ 411200: '三门峡市',
+ 411202: '湖滨区',
+ 411221: '渑池县',
+ 411222: '陕县',
+ 411224: '卢氏县',
+ 411281: '义马市',
+ 411282: '灵宝市',
+ 411283: '其它区',
+ 411300: '南阳市',
+ 411302: '宛城区',
+ 411303: '卧龙区',
+ 411321: '南召县',
+ 411322: '方城县',
+ 411323: '西峡县',
+ 411324: '镇平县',
+ 411325: '内乡县',
+ 411326: '淅川县',
+ 411327: '社旗县',
+ 411328: '唐河县',
+ 411329: '新野县',
+ 411330: '桐柏县',
+ 411381: '邓州市',
+ 411382: '其它区',
+ 411400: '商丘市',
+ 411402: '梁园区',
+ 411403: '睢阳区',
+ 411421: '民权县',
+ 411422: '睢县',
+ 411423: '宁陵县',
+ 411424: '柘城县',
+ 411425: '虞城县',
+ 411426: '夏邑县',
+ 411481: '永城市',
+ 411482: '其它区',
+ 411500: '信阳市',
+ 411502: '浉河区',
+ 411503: '平桥区',
+ 411521: '罗山县',
+ 411522: '光山县',
+ 411523: '新县',
+ 411524: '商城县',
+ 411525: '固始县',
+ 411526: '潢川县',
+ 411527: '淮滨县',
+ 411528: '息县',
+ 411529: '其它区',
+ 411600: '周口市',
+ 411602: '川汇区',
+ 411621: '扶沟县',
+ 411622: '西华县',
+ 411623: '商水县',
+ 411624: '沈丘县',
+ 411625: '郸城县',
+ 411626: '淮阳县',
+ 411627: '太康县',
+ 411628: '鹿邑县',
+ 411681: '项城市',
+ 411682: '其它区',
+ 411700: '驻马店市',
+ 411702: '驿城区',
+ 411721: '西平县',
+ 411722: '上蔡县',
+ 411723: '平舆县',
+ 411724: '正阳县',
+ 411725: '确山县',
+ 411726: '泌阳县',
+ 411727: '汝南县',
+ 411728: '遂平县',
+ 411729: '新蔡县',
+ 411730: '其它区',
+ 420000: '湖北省',
+ 420100: '武汉市',
+ 420102: '江岸区',
+ 420103: '江汉区',
+ 420104: '硚口区',
+ 420105: '汉阳区',
+ 420106: '武昌区',
+ 420107: '青山区',
+ 420111: '洪山区',
+ 420112: '东西湖区',
+ 420113: '汉南区',
+ 420114: '蔡甸区',
+ 420115: '江夏区',
+ 420116: '黄陂区',
+ 420117: '新洲区',
+ 420118: '其它区',
+ 420200: '黄石市',
+ 420202: '黄石港区',
+ 420203: '西塞山区',
+ 420204: '下陆区',
+ 420205: '铁山区',
+ 420222: '阳新县',
+ 420281: '大冶市',
+ 420282: '其它区',
+ 420300: '十堰市',
+ 420302: '茅箭区',
+ 420303: '张湾区',
+ 420321: '郧县',
+ 420322: '郧西县',
+ 420323: '竹山县',
+ 420324: '竹溪县',
+ 420325: '房县',
+ 420381: '丹江口市',
+ 420383: '其它区',
+ 420500: '宜昌市',
+ 420502: '西陵区',
+ 420503: '伍家岗区',
+ 420504: '点军区',
+ 420505: '猇亭区',
+ 420506: '夷陵区',
+ 420525: '远安县',
+ 420526: '兴山县',
+ 420527: '秭归县',
+ 420528: '长阳土家族自治县',
+ 420529: '五峰土家族自治县',
+ 420581: '宜都市',
+ 420582: '当阳市',
+ 420583: '枝江市',
+ 420584: '其它区',
+ 420600: '襄阳市',
+ 420602: '襄城区',
+ 420606: '樊城区',
+ 420607: '襄州区',
+ 420624: '南漳县',
+ 420625: '谷城县',
+ 420626: '保康县',
+ 420682: '老河口市',
+ 420683: '枣阳市',
+ 420684: '宜城市',
+ 420685: '其它区',
+ 420700: '鄂州市',
+ 420702: '梁子湖区',
+ 420703: '华容区',
+ 420704: '鄂城区',
+ 420705: '其它区',
+ 420800: '荆门市',
+ 420802: '东宝区',
+ 420804: '掇刀区',
+ 420821: '京山县',
+ 420822: '沙洋县',
+ 420881: '钟祥市',
+ 420882: '其它区',
+ 420900: '孝感市',
+ 420902: '孝南区',
+ 420921: '孝昌县',
+ 420922: '大悟县',
+ 420923: '云梦县',
+ 420981: '应城市',
+ 420982: '安陆市',
+ 420984: '汉川市',
+ 420985: '其它区',
+ 421000: '荆州市',
+ 421002: '沙市区',
+ 421003: '荆州区',
+ 421022: '公安县',
+ 421023: '监利县',
+ 421024: '江陵县',
+ 421081: '石首市',
+ 421083: '洪湖市',
+ 421087: '松滋市',
+ 421088: '其它区',
+ 421100: '黄冈市',
+ 421102: '黄州区',
+ 421121: '团风县',
+ 421122: '红安县',
+ 421123: '罗田县',
+ 421124: '英山县',
+ 421125: '浠水县',
+ 421126: '蕲春县',
+ 421127: '黄梅县',
+ 421181: '麻城市',
+ 421182: '武穴市',
+ 421183: '其它区',
+ 421200: '咸宁市',
+ 421202: '咸安区',
+ 421221: '嘉鱼县',
+ 421222: '通城县',
+ 421223: '崇阳县',
+ 421224: '通山县',
+ 421281: '赤壁市',
+ 421283: '其它区',
+ 421300: '随州市',
+ 421302: '曾都区',
+ 421321: '随县',
+ 421381: '广水市',
+ 421382: '其它区',
+ 422800: '恩施土家族苗族自治州',
+ 422801: '恩施市',
+ 422802: '利川市',
+ 422822: '建始县',
+ 422823: '巴东县',
+ 422825: '宣恩县',
+ 422826: '咸丰县',
+ 422827: '来凤县',
+ 422828: '鹤峰县',
+ 422829: '其它区',
+ 429004: '仙桃市',
+ 429005: '潜江市',
+ 429006: '天门市',
+ 429021: '神农架林区',
+ 430000: '湖南省',
+ 430100: '长沙市',
+ 430102: '芙蓉区',
+ 430103: '天心区',
+ 430104: '岳麓区',
+ 430105: '开福区',
+ 430111: '雨花区',
+ 430121: '长沙县',
+ 430122: '望城区',
+ 430124: '宁乡县',
+ 430181: '浏阳市',
+ 430182: '其它区',
+ 430200: '株洲市',
+ 430202: '荷塘区',
+ 430203: '芦淞区',
+ 430204: '石峰区',
+ 430211: '天元区',
+ 430221: '株洲县',
+ 430223: '攸县',
+ 430224: '茶陵县',
+ 430225: '炎陵县',
+ 430281: '醴陵市',
+ 430282: '其它区',
+ 430300: '湘潭市',
+ 430302: '雨湖区',
+ 430304: '岳塘区',
+ 430321: '湘潭县',
+ 430381: '湘乡市',
+ 430382: '韶山市',
+ 430383: '其它区',
+ 430400: '衡阳市',
+ 430405: '珠晖区',
+ 430406: '雁峰区',
+ 430407: '石鼓区',
+ 430408: '蒸湘区',
+ 430412: '南岳区',
+ 430421: '衡阳县',
+ 430422: '衡南县',
+ 430423: '衡山县',
+ 430424: '衡东县',
+ 430426: '祁东县',
+ 430481: '耒阳市',
+ 430482: '常宁市',
+ 430483: '其它区',
+ 430500: '邵阳市',
+ 430502: '双清区',
+ 430503: '大祥区',
+ 430511: '北塔区',
+ 430521: '邵东县',
+ 430522: '新邵县',
+ 430523: '邵阳县',
+ 430524: '隆回县',
+ 430525: '洞口县',
+ 430527: '绥宁县',
+ 430528: '新宁县',
+ 430529: '城步苗族自治县',
+ 430581: '武冈市',
+ 430582: '其它区',
+ 430600: '岳阳市',
+ 430602: '岳阳楼区',
+ 430603: '云溪区',
+ 430611: '君山区',
+ 430621: '岳阳县',
+ 430623: '华容县',
+ 430624: '湘阴县',
+ 430626: '平江县',
+ 430681: '汨罗市',
+ 430682: '临湘市',
+ 430683: '其它区',
+ 430700: '常德市',
+ 430702: '武陵区',
+ 430703: '鼎城区',
+ 430721: '安乡县',
+ 430722: '汉寿县',
+ 430723: '澧县',
+ 430724: '临澧县',
+ 430725: '桃源县',
+ 430726: '石门县',
+ 430781: '津市市',
+ 430782: '其它区',
+ 430800: '张家界市',
+ 430802: '永定区',
+ 430811: '武陵源区',
+ 430821: '慈利县',
+ 430822: '桑植县',
+ 430823: '其它区',
+ 430900: '益阳市',
+ 430902: '资阳区',
+ 430903: '赫山区',
+ 430921: '南县',
+ 430922: '桃江县',
+ 430923: '安化县',
+ 430981: '沅江市',
+ 430982: '其它区',
+ 431000: '郴州市',
+ 431002: '北湖区',
+ 431003: '苏仙区',
+ 431021: '桂阳县',
+ 431022: '宜章县',
+ 431023: '永兴县',
+ 431024: '嘉禾县',
+ 431025: '临武县',
+ 431026: '汝城县',
+ 431027: '桂东县',
+ 431028: '安仁县',
+ 431081: '资兴市',
+ 431082: '其它区',
+ 431100: '永州市',
+ 431102: '零陵区',
+ 431103: '冷水滩区',
+ 431121: '祁阳县',
+ 431122: '东安县',
+ 431123: '双牌县',
+ 431124: '道县',
+ 431125: '江永县',
+ 431126: '宁远县',
+ 431127: '蓝山县',
+ 431128: '新田县',
+ 431129: '江华瑶族自治县',
+ 431130: '其它区',
+ 431200: '怀化市',
+ 431202: '鹤城区',
+ 431221: '中方县',
+ 431222: '沅陵县',
+ 431223: '辰溪县',
+ 431224: '溆浦县',
+ 431225: '会同县',
+ 431226: '麻阳苗族自治县',
+ 431227: '新晃侗族自治县',
+ 431228: '芷江侗族自治县',
+ 431229: '靖州苗族侗族自治县',
+ 431230: '通道侗族自治县',
+ 431281: '洪江市',
+ 431282: '其它区',
+ 431300: '娄底市',
+ 431302: '娄星区',
+ 431321: '双峰县',
+ 431322: '新化县',
+ 431381: '冷水江市',
+ 431382: '涟源市',
+ 431383: '其它区',
+ 433100: '湘西土家族苗族自治州',
+ 433101: '吉首市',
+ 433122: '泸溪县',
+ 433123: '凤凰县',
+ 433124: '花垣县',
+ 433125: '保靖县',
+ 433126: '古丈县',
+ 433127: '永顺县',
+ 433130: '龙山县',
+ 433131: '其它区',
+ 440000: '广东省',
+ 440100: '广州市',
+ 440103: '荔湾区',
+ 440104: '越秀区',
+ 440105: '海珠区',
+ 440106: '天河区',
+ 440111: '白云区',
+ 440112: '黄埔区',
+ 440113: '番禺区',
+ 440114: '花都区',
+ 440115: '南沙区',
+ 440116: '萝岗区',
+ 440183: '增城市',
+ 440184: '从化市',
+ 440189: '其它区',
+ 440200: '韶关市',
+ 440203: '武江区',
+ 440204: '浈江区',
+ 440205: '曲江区',
+ 440222: '始兴县',
+ 440224: '仁化县',
+ 440229: '翁源县',
+ 440232: '乳源瑶族自治县',
+ 440233: '新丰县',
+ 440281: '乐昌市',
+ 440282: '南雄市',
+ 440283: '其它区',
+ 440300: '深圳市',
+ 440303: '罗湖区',
+ 440304: '福田区',
+ 440305: '南山区',
+ 440306: '宝安区',
+ 440307: '龙岗区',
+ 440308: '盐田区',
+ 440309: '其它区',
+ 440320: '光明新区',
+ 440321: '坪山新区',
+ 440322: '大鹏新区',
+ 440323: '龙华新区',
+ 440400: '珠海市',
+ 440402: '香洲区',
+ 440403: '斗门区',
+ 440404: '金湾区',
+ 440488: '其它区',
+ 440500: '汕头市',
+ 440507: '龙湖区',
+ 440511: '金平区',
+ 440512: '濠江区',
+ 440513: '潮阳区',
+ 440514: '潮南区',
+ 440515: '澄海区',
+ 440523: '南澳县',
+ 440524: '其它区',
+ 440600: '佛山市',
+ 440604: '禅城区',
+ 440605: '南海区',
+ 440606: '顺德区',
+ 440607: '三水区',
+ 440608: '高明区',
+ 440609: '其它区',
+ 440700: '江门市',
+ 440703: '蓬江区',
+ 440704: '江海区',
+ 440705: '新会区',
+ 440781: '台山市',
+ 440783: '开平市',
+ 440784: '鹤山市',
+ 440785: '恩平市',
+ 440786: '其它区',
+ 440800: '湛江市',
+ 440802: '赤坎区',
+ 440803: '霞山区',
+ 440804: '坡头区',
+ 440811: '麻章区',
+ 440823: '遂溪县',
+ 440825: '徐闻县',
+ 440881: '廉江市',
+ 440882: '雷州市',
+ 440883: '吴川市',
+ 440884: '其它区',
+ 440900: '茂名市',
+ 440902: '茂南区',
+ 440903: '茂港区',
+ 440923: '电白县',
+ 440981: '高州市',
+ 440982: '化州市',
+ 440983: '信宜市',
+ 440984: '其它区',
+ 441200: '肇庆市',
+ 441202: '端州区',
+ 441203: '鼎湖区',
+ 441223: '广宁县',
+ 441224: '怀集县',
+ 441225: '封开县',
+ 441226: '德庆县',
+ 441283: '高要市',
+ 441284: '四会市',
+ 441285: '其它区',
+ 441300: '惠州市',
+ 441302: '惠城区',
+ 441303: '惠阳区',
+ 441322: '博罗县',
+ 441323: '惠东县',
+ 441324: '龙门县',
+ 441325: '其它区',
+ 441400: '梅州市',
+ 441402: '梅江区',
+ 441421: '梅县',
+ 441422: '大埔县',
+ 441423: '丰顺县',
+ 441424: '五华县',
+ 441426: '平远县',
+ 441427: '蕉岭县',
+ 441481: '兴宁市',
+ 441482: '其它区',
+ 441500: '汕尾市',
+ 441502: '城区',
+ 441521: '海丰县',
+ 441523: '陆河县',
+ 441581: '陆丰市',
+ 441582: '其它区',
+ 441600: '河源市',
+ 441602: '源城区',
+ 441621: '紫金县',
+ 441622: '龙川县',
+ 441623: '连平县',
+ 441624: '和平县',
+ 441625: '东源县',
+ 441626: '其它区',
+ 441700: '阳江市',
+ 441702: '江城区',
+ 441721: '阳西县',
+ 441723: '阳东县',
+ 441781: '阳春市',
+ 441782: '其它区',
+ 441800: '清远市',
+ 441802: '清城区',
+ 441821: '佛冈县',
+ 441823: '阳山县',
+ 441825: '连山壮族瑶族自治县',
+ 441826: '连南瑶族自治县',
+ 441827: '清新区',
+ 441881: '英德市',
+ 441882: '连州市',
+ 441883: '其它区',
+ 441900: '东莞市',
+ 442000: '中山市',
+ 442101: '东沙群岛',
+ 445100: '潮州市',
+ 445102: '湘桥区',
+ 445121: '潮安区',
+ 445122: '饶平县',
+ 445186: '其它区',
+ 445200: '揭阳市',
+ 445202: '榕城区',
+ 445221: '揭东区',
+ 445222: '揭西县',
+ 445224: '惠来县',
+ 445281: '普宁市',
+ 445285: '其它区',
+ 445300: '云浮市',
+ 445302: '云城区',
+ 445321: '新兴县',
+ 445322: '郁南县',
+ 445323: '云安县',
+ 445381: '罗定市',
+ 445382: '其它区',
+ 450000: '广西壮族自治区',
+ 450100: '南宁市',
+ 450102: '兴宁区',
+ 450103: '青秀区',
+ 450105: '江南区',
+ 450107: '西乡塘区',
+ 450108: '良庆区',
+ 450109: '邕宁区',
+ 450122: '武鸣县',
+ 450123: '隆安县',
+ 450124: '马山县',
+ 450125: '上林县',
+ 450126: '宾阳县',
+ 450127: '横县',
+ 450128: '其它区',
+ 450200: '柳州市',
+ 450202: '城中区',
+ 450203: '鱼峰区',
+ 450204: '柳南区',
+ 450205: '柳北区',
+ 450221: '柳江县',
+ 450222: '柳城县',
+ 450223: '鹿寨县',
+ 450224: '融安县',
+ 450225: '融水苗族自治县',
+ 450226: '三江侗族自治县',
+ 450227: '其它区',
+ 450300: '桂林市',
+ 450302: '秀峰区',
+ 450303: '叠彩区',
+ 450304: '象山区',
+ 450305: '七星区',
+ 450311: '雁山区',
+ 450321: '阳朔县',
+ 450322: '临桂区',
+ 450323: '灵川县',
+ 450324: '全州县',
+ 450325: '兴安县',
+ 450326: '永福县',
+ 450327: '灌阳县',
+ 450328: '龙胜各族自治县',
+ 450329: '资源县',
+ 450330: '平乐县',
+ 450331: '荔浦县',
+ 450332: '恭城瑶族自治县',
+ 450333: '其它区',
+ 450400: '梧州市',
+ 450403: '万秀区',
+ 450405: '长洲区',
+ 450406: '龙圩区',
+ 450421: '苍梧县',
+ 450422: '藤县',
+ 450423: '蒙山县',
+ 450481: '岑溪市',
+ 450482: '其它区',
+ 450500: '北海市',
+ 450502: '海城区',
+ 450503: '银海区',
+ 450512: '铁山港区',
+ 450521: '合浦县',
+ 450522: '其它区',
+ 450600: '防城港市',
+ 450602: '港口区',
+ 450603: '防城区',
+ 450621: '上思县',
+ 450681: '东兴市',
+ 450682: '其它区',
+ 450700: '钦州市',
+ 450702: '钦南区',
+ 450703: '钦北区',
+ 450721: '灵山县',
+ 450722: '浦北县',
+ 450723: '其它区',
+ 450800: '贵港市',
+ 450802: '港北区',
+ 450803: '港南区',
+ 450804: '覃塘区',
+ 450821: '平南县',
+ 450881: '桂平市',
+ 450882: '其它区',
+ 450900: '玉林市',
+ 450902: '玉州区',
+ 450903: '福绵区',
+ 450921: '容县',
+ 450922: '陆川县',
+ 450923: '博白县',
+ 450924: '兴业县',
+ 450981: '北流市',
+ 450982: '其它区',
+ 451000: '百色市',
+ 451002: '右江区',
+ 451021: '田阳县',
+ 451022: '田东县',
+ 451023: '平果县',
+ 451024: '德保县',
+ 451025: '靖西县',
+ 451026: '那坡县',
+ 451027: '凌云县',
+ 451028: '乐业县',
+ 451029: '田林县',
+ 451030: '西林县',
+ 451031: '隆林各族自治县',
+ 451032: '其它区',
+ 451100: '贺州市',
+ 451102: '八步区',
+ 451119: '平桂管理区',
+ 451121: '昭平县',
+ 451122: '钟山县',
+ 451123: '富川瑶族自治县',
+ 451124: '其它区',
+ 451200: '河池市',
+ 451202: '金城江区',
+ 451221: '南丹县',
+ 451222: '天峨县',
+ 451223: '凤山县',
+ 451224: '东兰县',
+ 451225: '罗城仫佬族自治县',
+ 451226: '环江毛南族自治县',
+ 451227: '巴马瑶族自治县',
+ 451228: '都安瑶族自治县',
+ 451229: '大化瑶族自治县',
+ 451281: '宜州市',
+ 451282: '其它区',
+ 451300: '来宾市',
+ 451302: '兴宾区',
+ 451321: '忻城县',
+ 451322: '象州县',
+ 451323: '武宣县',
+ 451324: '金秀瑶族自治县',
+ 451381: '合山市',
+ 451382: '其它区',
+ 451400: '崇左市',
+ 451402: '江州区',
+ 451421: '扶绥县',
+ 451422: '宁明县',
+ 451423: '龙州县',
+ 451424: '大新县',
+ 451425: '天等县',
+ 451481: '凭祥市',
+ 451482: '其它区',
+ 460000: '海南省',
+ 460100: '海口市',
+ 460105: '秀英区',
+ 460106: '龙华区',
+ 460107: '琼山区',
+ 460108: '美兰区',
+ 460109: '其它区',
+ 460200: '三亚市',
+ 460300: '三沙市',
+ 460321: '西沙群岛',
+ 460322: '南沙群岛',
+ 460323: '中沙群岛的岛礁及其海域',
+ 469001: '五指山市',
+ 469002: '琼海市',
+ 469003: '儋州市',
+ 469005: '文昌市',
+ 469006: '万宁市',
+ 469007: '东方市',
+ 469025: '定安县',
+ 469026: '屯昌县',
+ 469027: '澄迈县',
+ 469028: '临高县',
+ 469030: '白沙黎族自治县',
+ 469031: '昌江黎族自治县',
+ 469033: '乐东黎族自治县',
+ 469034: '陵水黎族自治县',
+ 469035: '保亭黎族苗族自治县',
+ 469036: '琼中黎族苗族自治县',
+ 471005: '其它区',
+ 500000: '重庆',
+ 500100: '重庆市',
+ 500101: '万州区',
+ 500102: '涪陵区',
+ 500103: '渝中区',
+ 500104: '大渡口区',
+ 500105: '江北区',
+ 500106: '沙坪坝区',
+ 500107: '九龙坡区',
+ 500108: '南岸区',
+ 500109: '北碚区',
+ 500110: '万盛区',
+ 500111: '双桥区',
+ 500112: '渝北区',
+ 500113: '巴南区',
+ 500114: '黔江区',
+ 500115: '长寿区',
+ 500222: '綦江区',
+ 500223: '潼南县',
+ 500224: '铜梁县',
+ 500225: '大足区',
+ 500226: '荣昌县',
+ 500227: '璧山县',
+ 500228: '梁平县',
+ 500229: '城口县',
+ 500230: '丰都县',
+ 500231: '垫江县',
+ 500232: '武隆县',
+ 500233: '忠县',
+ 500234: '开县',
+ 500235: '云阳县',
+ 500236: '奉节县',
+ 500237: '巫山县',
+ 500238: '巫溪县',
+ 500240: '石柱土家族自治县',
+ 500241: '秀山土家族苗族自治县',
+ 500242: '酉阳土家族苗族自治县',
+ 500243: '彭水苗族土家族自治县',
+ 500381: '江津区',
+ 500382: '合川区',
+ 500383: '永川区',
+ 500384: '南川区',
+ 500385: '其它区',
+ 510000: '四川省',
+ 510100: '成都市',
+ 510104: '锦江区',
+ 510105: '青羊区',
+ 510106: '金牛区',
+ 510107: '武侯区',
+ 510108: '成华区',
+ 510112: '龙泉驿区',
+ 510113: '青白江区',
+ 510114: '新都区',
+ 510115: '温江区',
+ 510121: '金堂县',
+ 510122: '双流县',
+ 510124: '郫县',
+ 510129: '大邑县',
+ 510131: '蒲江县',
+ 510132: '新津县',
+ 510181: '都江堰市',
+ 510182: '彭州市',
+ 510183: '邛崃市',
+ 510184: '崇州市',
+ 510185: '其它区',
+ 510300: '自贡市',
+ 510302: '自流井区',
+ 510303: '贡井区',
+ 510304: '大安区',
+ 510311: '沿滩区',
+ 510321: '荣县',
+ 510322: '富顺县',
+ 510323: '其它区',
+ 510400: '攀枝花市',
+ 510402: '东区',
+ 510403: '西区',
+ 510411: '仁和区',
+ 510421: '米易县',
+ 510422: '盐边县',
+ 510423: '其它区',
+ 510500: '泸州市',
+ 510502: '江阳区',
+ 510503: '纳溪区',
+ 510504: '龙马潭区',
+ 510521: '泸县',
+ 510522: '合江县',
+ 510524: '叙永县',
+ 510525: '古蔺县',
+ 510526: '其它区',
+ 510600: '德阳市',
+ 510603: '旌阳区',
+ 510623: '中江县',
+ 510626: '罗江县',
+ 510681: '广汉市',
+ 510682: '什邡市',
+ 510683: '绵竹市',
+ 510684: '其它区',
+ 510700: '绵阳市',
+ 510703: '涪城区',
+ 510704: '游仙区',
+ 510722: '三台县',
+ 510723: '盐亭县',
+ 510724: '安县',
+ 510725: '梓潼县',
+ 510726: '北川羌族自治县',
+ 510727: '平武县',
+ 510781: '江油市',
+ 510782: '其它区',
+ 510800: '广元市',
+ 510802: '利州区',
+ 510811: '昭化区',
+ 510812: '朝天区',
+ 510821: '旺苍县',
+ 510822: '青川县',
+ 510823: '剑阁县',
+ 510824: '苍溪县',
+ 510825: '其它区',
+ 510900: '遂宁市',
+ 510903: '船山区',
+ 510904: '安居区',
+ 510921: '蓬溪县',
+ 510922: '射洪县',
+ 510923: '大英县',
+ 510924: '其它区',
+ 511000: '内江市',
+ 511002: '市中区',
+ 511011: '东兴区',
+ 511024: '威远县',
+ 511025: '资中县',
+ 511028: '隆昌县',
+ 511029: '其它区',
+ 511100: '乐山市',
+ 511102: '市中区',
+ 511111: '沙湾区',
+ 511112: '五通桥区',
+ 511113: '金口河区',
+ 511123: '犍为县',
+ 511124: '井研县',
+ 511126: '夹江县',
+ 511129: '沐川县',
+ 511132: '峨边彝族自治县',
+ 511133: '马边彝族自治县',
+ 511181: '峨眉山市',
+ 511182: '其它区',
+ 511300: '南充市',
+ 511302: '顺庆区',
+ 511303: '高坪区',
+ 511304: '嘉陵区',
+ 511321: '南部县',
+ 511322: '营山县',
+ 511323: '蓬安县',
+ 511324: '仪陇县',
+ 511325: '西充县',
+ 511381: '阆中市',
+ 511382: '其它区',
+ 511400: '眉山市',
+ 511402: '东坡区',
+ 511421: '仁寿县',
+ 511422: '彭山县',
+ 511423: '洪雅县',
+ 511424: '丹棱县',
+ 511425: '青神县',
+ 511426: '其它区',
+ 511500: '宜宾市',
+ 511502: '翠屏区',
+ 511521: '宜宾县',
+ 511522: '南溪区',
+ 511523: '江安县',
+ 511524: '长宁县',
+ 511525: '高县',
+ 511526: '珙县',
+ 511527: '筠连县',
+ 511528: '兴文县',
+ 511529: '屏山县',
+ 511530: '其它区',
+ 511600: '广安市',
+ 511602: '广安区',
+ 511603: '前锋区',
+ 511621: '岳池县',
+ 511622: '武胜县',
+ 511623: '邻水县',
+ 511681: '华蓥市',
+ 511683: '其它区',
+ 511700: '达州市',
+ 511702: '通川区',
+ 511721: '达川区',
+ 511722: '宣汉县',
+ 511723: '开江县',
+ 511724: '大竹县',
+ 511725: '渠县',
+ 511781: '万源市',
+ 511782: '其它区',
+ 511800: '雅安市',
+ 511802: '雨城区',
+ 511821: '名山区',
+ 511822: '荥经县',
+ 511823: '汉源县',
+ 511824: '石棉县',
+ 511825: '天全县',
+ 511826: '芦山县',
+ 511827: '宝兴县',
+ 511828: '其它区',
+ 511900: '巴中市',
+ 511902: '巴州区',
+ 511903: '恩阳区',
+ 511921: '通江县',
+ 511922: '南江县',
+ 511923: '平昌县',
+ 511924: '其它区',
+ 512000: '资阳市',
+ 512002: '雁江区',
+ 512021: '安岳县',
+ 512022: '乐至县',
+ 512081: '简阳市',
+ 512082: '其它区',
+ 513200: '阿坝藏族羌族自治州',
+ 513221: '汶川县',
+ 513222: '理县',
+ 513223: '茂县',
+ 513224: '松潘县',
+ 513225: '九寨沟县',
+ 513226: '金川县',
+ 513227: '小金县',
+ 513228: '黑水县',
+ 513229: '马尔康县',
+ 513230: '壤塘县',
+ 513231: '阿坝县',
+ 513232: '若尔盖县',
+ 513233: '红原县',
+ 513234: '其它区',
+ 513300: '甘孜藏族自治州',
+ 513321: '康定县',
+ 513322: '泸定县',
+ 513323: '丹巴县',
+ 513324: '九龙县',
+ 513325: '雅江县',
+ 513326: '道孚县',
+ 513327: '炉霍县',
+ 513328: '甘孜县',
+ 513329: '新龙县',
+ 513330: '德格县',
+ 513331: '白玉县',
+ 513332: '石渠县',
+ 513333: '色达县',
+ 513334: '理塘县',
+ 513335: '巴塘县',
+ 513336: '乡城县',
+ 513337: '稻城县',
+ 513338: '得荣县',
+ 513339: '其它区',
+ 513400: '凉山彝族自治州',
+ 513401: '西昌市',
+ 513422: '木里藏族自治县',
+ 513423: '盐源县',
+ 513424: '德昌县',
+ 513425: '会理县',
+ 513426: '会东县',
+ 513427: '宁南县',
+ 513428: '普格县',
+ 513429: '布拖县',
+ 513430: '金阳县',
+ 513431: '昭觉县',
+ 513432: '喜德县',
+ 513433: '冕宁县',
+ 513434: '越西县',
+ 513435: '甘洛县',
+ 513436: '美姑县',
+ 513437: '雷波县',
+ 513438: '其它区',
+ 520000: '贵州省',
+ 520100: '贵阳市',
+ 520102: '南明区',
+ 520103: '云岩区',
+ 520111: '花溪区',
+ 520112: '乌当区',
+ 520113: '白云区',
+ 520121: '开阳县',
+ 520122: '息烽县',
+ 520123: '修文县',
+ 520151: '观山湖区',
+ 520181: '清镇市',
+ 520182: '其它区',
+ 520200: '六盘水市',
+ 520201: '钟山区',
+ 520203: '六枝特区',
+ 520221: '水城县',
+ 520222: '盘县',
+ 520223: '其它区',
+ 520300: '遵义市',
+ 520302: '红花岗区',
+ 520303: '汇川区',
+ 520321: '遵义县',
+ 520322: '桐梓县',
+ 520323: '绥阳县',
+ 520324: '正安县',
+ 520325: '道真仡佬族苗族自治县',
+ 520326: '务川仡佬族苗族自治县',
+ 520327: '凤冈县',
+ 520328: '湄潭县',
+ 520329: '余庆县',
+ 520330: '习水县',
+ 520381: '赤水市',
+ 520382: '仁怀市',
+ 520383: '其它区',
+ 520400: '安顺市',
+ 520402: '西秀区',
+ 520421: '平坝县',
+ 520422: '普定县',
+ 520423: '镇宁布依族苗族自治县',
+ 520424: '关岭布依族苗族自治县',
+ 520425: '紫云苗族布依族自治县',
+ 520426: '其它区',
+ 522200: '铜仁市',
+ 522201: '碧江区',
+ 522222: '江口县',
+ 522223: '玉屏侗族自治县',
+ 522224: '石阡县',
+ 522225: '思南县',
+ 522226: '印江土家族苗族自治县',
+ 522227: '德江县',
+ 522228: '沿河土家族自治县',
+ 522229: '松桃苗族自治县',
+ 522230: '万山区',
+ 522231: '其它区',
+ 522300: '黔西南布依族苗族自治州',
+ 522301: '兴义市',
+ 522322: '兴仁县',
+ 522323: '普安县',
+ 522324: '晴隆县',
+ 522325: '贞丰县',
+ 522326: '望谟县',
+ 522327: '册亨县',
+ 522328: '安龙县',
+ 522329: '其它区',
+ 522400: '毕节市',
+ 522401: '七星关区',
+ 522422: '大方县',
+ 522423: '黔西县',
+ 522424: '金沙县',
+ 522425: '织金县',
+ 522426: '纳雍县',
+ 522427: '威宁彝族回族苗族自治县',
+ 522428: '赫章县',
+ 522429: '其它区',
+ 522600: '黔东南苗族侗族自治州',
+ 522601: '凯里市',
+ 522622: '黄平县',
+ 522623: '施秉县',
+ 522624: '三穗县',
+ 522625: '镇远县',
+ 522626: '岑巩县',
+ 522627: '天柱县',
+ 522628: '锦屏县',
+ 522629: '剑河县',
+ 522630: '台江县',
+ 522631: '黎平县',
+ 522632: '榕江县',
+ 522633: '从江县',
+ 522634: '雷山县',
+ 522635: '麻江县',
+ 522636: '丹寨县',
+ 522637: '其它区',
+ 522700: '黔南布依族苗族自治州',
+ 522701: '都匀市',
+ 522702: '福泉市',
+ 522722: '荔波县',
+ 522723: '贵定县',
+ 522725: '瓮安县',
+ 522726: '独山县',
+ 522727: '平塘县',
+ 522728: '罗甸县',
+ 522729: '长顺县',
+ 522730: '龙里县',
+ 522731: '惠水县',
+ 522732: '三都水族自治县',
+ 522733: '其它区',
+ 530000: '云南省',
+ 530100: '昆明市',
+ 530102: '五华区',
+ 530103: '盘龙区',
+ 530111: '官渡区',
+ 530112: '西山区',
+ 530113: '东川区',
+ 530121: '呈贡区',
+ 530122: '晋宁县',
+ 530124: '富民县',
+ 530125: '宜良县',
+ 530126: '石林彝族自治县',
+ 530127: '嵩明县',
+ 530128: '禄劝彝族苗族自治县',
+ 530129: '寻甸回族彝族自治县',
+ 530181: '安宁市',
+ 530182: '其它区',
+ 530300: '曲靖市',
+ 530302: '麒麟区',
+ 530321: '马龙县',
+ 530322: '陆良县',
+ 530323: '师宗县',
+ 530324: '罗平县',
+ 530325: '富源县',
+ 530326: '会泽县',
+ 530328: '沾益县',
+ 530381: '宣威市',
+ 530382: '其它区',
+ 530400: '玉溪市',
+ 530402: '红塔区',
+ 530421: '江川县',
+ 530422: '澄江县',
+ 530423: '通海县',
+ 530424: '华宁县',
+ 530425: '易门县',
+ 530426: '峨山彝族自治县',
+ 530427: '新平彝族傣族自治县',
+ 530428: '元江哈尼族彝族傣族自治县',
+ 530429: '其它区',
+ 530500: '保山市',
+ 530502: '隆阳区',
+ 530521: '施甸县',
+ 530522: '腾冲县',
+ 530523: '龙陵县',
+ 530524: '昌宁县',
+ 530525: '其它区',
+ 530600: '昭通市',
+ 530602: '昭阳区',
+ 530621: '鲁甸县',
+ 530622: '巧家县',
+ 530623: '盐津县',
+ 530624: '大关县',
+ 530625: '永善县',
+ 530626: '绥江县',
+ 530627: '镇雄县',
+ 530628: '彝良县',
+ 530629: '威信县',
+ 530630: '水富县',
+ 530631: '其它区',
+ 530700: '丽江市',
+ 530702: '古城区',
+ 530721: '玉龙纳西族自治县',
+ 530722: '永胜县',
+ 530723: '华坪县',
+ 530724: '宁蒗彝族自治县',
+ 530725: '其它区',
+ 530800: '普洱市',
+ 530802: '思茅区',
+ 530821: '宁洱哈尼族彝族自治县',
+ 530822: '墨江哈尼族自治县',
+ 530823: '景东彝族自治县',
+ 530824: '景谷傣族彝族自治县',
+ 530825: '镇沅彝族哈尼族拉祜族自治县',
+ 530826: '江城哈尼族彝族自治县',
+ 530827: '孟连傣族拉祜族佤族自治县',
+ 530828: '澜沧拉祜族自治县',
+ 530829: '西盟佤族自治县',
+ 530830: '其它区',
+ 530900: '临沧市',
+ 530902: '临翔区',
+ 530921: '凤庆县',
+ 530922: '云县',
+ 530923: '永德县',
+ 530924: '镇康县',
+ 530925: '双江拉祜族佤族布朗族傣族自治县',
+ 530926: '耿马傣族佤族自治县',
+ 530927: '沧源佤族自治县',
+ 530928: '其它区',
+ 532300: '楚雄彝族自治州',
+ 532301: '楚雄市',
+ 532322: '双柏县',
+ 532323: '牟定县',
+ 532324: '南华县',
+ 532325: '姚安县',
+ 532326: '大姚县',
+ 532327: '永仁县',
+ 532328: '元谋县',
+ 532329: '武定县',
+ 532331: '禄丰县',
+ 532332: '其它区',
+ 532500: '红河哈尼族彝族自治州',
+ 532501: '个旧市',
+ 532502: '开远市',
+ 532522: '蒙自市',
+ 532523: '屏边苗族自治县',
+ 532524: '建水县',
+ 532525: '石屏县',
+ 532526: '弥勒市',
+ 532527: '泸西县',
+ 532528: '元阳县',
+ 532529: '红河县',
+ 532530: '金平苗族瑶族傣族自治县',
+ 532531: '绿春县',
+ 532532: '河口瑶族自治县',
+ 532533: '其它区',
+ 532600: '文山壮族苗族自治州',
+ 532621: '文山市',
+ 532622: '砚山县',
+ 532623: '西畴县',
+ 532624: '麻栗坡县',
+ 532625: '马关县',
+ 532626: '丘北县',
+ 532627: '广南县',
+ 532628: '富宁县',
+ 532629: '其它区',
+ 532800: '西双版纳傣族自治州',
+ 532801: '景洪市',
+ 532822: '勐海县',
+ 532823: '勐腊县',
+ 532824: '其它区',
+ 532900: '大理白族自治州',
+ 532901: '大理市',
+ 532922: '漾濞彝族自治县',
+ 532923: '祥云县',
+ 532924: '宾川县',
+ 532925: '弥渡县',
+ 532926: '南涧彝族自治县',
+ 532927: '巍山彝族回族自治县',
+ 532928: '永平县',
+ 532929: '云龙县',
+ 532930: '洱源县',
+ 532931: '剑川县',
+ 532932: '鹤庆县',
+ 532933: '其它区',
+ 533100: '德宏傣族景颇族自治州',
+ 533102: '瑞丽市',
+ 533103: '芒市',
+ 533122: '梁河县',
+ 533123: '盈江县',
+ 533124: '陇川县',
+ 533125: '其它区',
+ 533300: '怒江傈僳族自治州',
+ 533321: '泸水县',
+ 533323: '福贡县',
+ 533324: '贡山独龙族怒族自治县',
+ 533325: '兰坪白族普米族自治县',
+ 533326: '其它区',
+ 533400: '迪庆藏族自治州',
+ 533421: '香格里拉县',
+ 533422: '德钦县',
+ 533423: '维西傈僳族自治县',
+ 533424: '其它区',
+ 540000: '西藏自治区',
+ 540100: '拉萨市',
+ 540102: '城关区',
+ 540121: '林周县',
+ 540122: '当雄县',
+ 540123: '尼木县',
+ 540124: '曲水县',
+ 540125: '堆龙德庆县',
+ 540126: '达孜县',
+ 540127: '墨竹工卡县',
+ 540128: '其它区',
+ 542100: '昌都地区',
+ 542121: '昌都县',
+ 542122: '江达县',
+ 542123: '贡觉县',
+ 542124: '类乌齐县',
+ 542125: '丁青县',
+ 542126: '察雅县',
+ 542127: '八宿县',
+ 542128: '左贡县',
+ 542129: '芒康县',
+ 542132: '洛隆县',
+ 542133: '边坝县',
+ 542134: '其它区',
+ 542200: '山南地区',
+ 542221: '乃东县',
+ 542222: '扎囊县',
+ 542223: '贡嘎县',
+ 542224: '桑日县',
+ 542225: '琼结县',
+ 542226: '曲松县',
+ 542227: '措美县',
+ 542228: '洛扎县',
+ 542229: '加查县',
+ 542231: '隆子县',
+ 542232: '错那县',
+ 542233: '浪卡子县',
+ 542234: '其它区',
+ 542300: '日喀则地区',
+ 542301: '日喀则市',
+ 542322: '南木林县',
+ 542323: '江孜县',
+ 542324: '定日县',
+ 542325: '萨迦县',
+ 542326: '拉孜县',
+ 542327: '昂仁县',
+ 542328: '谢通门县',
+ 542329: '白朗县',
+ 542330: '仁布县',
+ 542331: '康马县',
+ 542332: '定结县',
+ 542333: '仲巴县',
+ 542334: '亚东县',
+ 542335: '吉隆县',
+ 542336: '聂拉木县',
+ 542337: '萨嘎县',
+ 542338: '岗巴县',
+ 542339: '其它区',
+ 542400: '那曲地区',
+ 542421: '那曲县',
+ 542422: '嘉黎县',
+ 542423: '比如县',
+ 542424: '聂荣县',
+ 542425: '安多县',
+ 542426: '申扎县',
+ 542427: '索县',
+ 542428: '班戈县',
+ 542429: '巴青县',
+ 542430: '尼玛县',
+ 542431: '其它区',
+ 542432: '双湖县',
+ 542500: '阿里地区',
+ 542521: '普兰县',
+ 542522: '札达县',
+ 542523: '噶尔县',
+ 542524: '日土县',
+ 542525: '革吉县',
+ 542526: '改则县',
+ 542527: '措勤县',
+ 542528: '其它区',
+ 542600: '林芝地区',
+ 542621: '林芝县',
+ 542622: '工布江达县',
+ 542623: '米林县',
+ 542624: '墨脱县',
+ 542625: '波密县',
+ 542626: '察隅县',
+ 542627: '朗县',
+ 542628: '其它区',
+ 610000: '陕西省',
+ 610100: '西安市',
+ 610102: '新城区',
+ 610103: '碑林区',
+ 610104: '莲湖区',
+ 610111: '灞桥区',
+ 610112: '未央区',
+ 610113: '雁塔区',
+ 610114: '阎良区',
+ 610115: '临潼区',
+ 610116: '长安区',
+ 610122: '蓝田县',
+ 610124: '周至县',
+ 610125: '户县',
+ 610126: '高陵县',
+ 610127: '其它区',
+ 610200: '铜川市',
+ 610202: '王益区',
+ 610203: '印台区',
+ 610204: '耀州区',
+ 610222: '宜君县',
+ 610223: '其它区',
+ 610300: '宝鸡市',
+ 610302: '渭滨区',
+ 610303: '金台区',
+ 610304: '陈仓区',
+ 610322: '凤翔县',
+ 610323: '岐山县',
+ 610324: '扶风县',
+ 610326: '眉县',
+ 610327: '陇县',
+ 610328: '千阳县',
+ 610329: '麟游县',
+ 610330: '凤县',
+ 610331: '太白县',
+ 610332: '其它区',
+ 610400: '咸阳市',
+ 610402: '秦都区',
+ 610403: '杨陵区',
+ 610404: '渭城区',
+ 610422: '三原县',
+ 610423: '泾阳县',
+ 610424: '乾县',
+ 610425: '礼泉县',
+ 610426: '永寿县',
+ 610427: '彬县',
+ 610428: '长武县',
+ 610429: '旬邑县',
+ 610430: '淳化县',
+ 610431: '武功县',
+ 610481: '兴平市',
+ 610482: '其它区',
+ 610500: '渭南市',
+ 610502: '临渭区',
+ 610521: '华县',
+ 610522: '潼关县',
+ 610523: '大荔县',
+ 610524: '合阳县',
+ 610525: '澄城县',
+ 610526: '蒲城县',
+ 610527: '白水县',
+ 610528: '富平县',
+ 610581: '韩城市',
+ 610582: '华阴市',
+ 610583: '其它区',
+ 610600: '延安市',
+ 610602: '宝塔区',
+ 610621: '延长县',
+ 610622: '延川县',
+ 610623: '子长县',
+ 610624: '安塞县',
+ 610625: '志丹县',
+ 610626: '吴起县',
+ 610627: '甘泉县',
+ 610628: '富县',
+ 610629: '洛川县',
+ 610630: '宜川县',
+ 610631: '黄龙县',
+ 610632: '黄陵县',
+ 610633: '其它区',
+ 610700: '汉中市',
+ 610702: '汉台区',
+ 610721: '南郑县',
+ 610722: '城固县',
+ 610723: '洋县',
+ 610724: '西乡县',
+ 610725: '勉县',
+ 610726: '宁强县',
+ 610727: '略阳县',
+ 610728: '镇巴县',
+ 610729: '留坝县',
+ 610730: '佛坪县',
+ 610731: '其它区',
+ 610800: '榆林市',
+ 610802: '榆阳区',
+ 610821: '神木县',
+ 610822: '府谷县',
+ 610823: '横山县',
+ 610824: '靖边县',
+ 610825: '定边县',
+ 610826: '绥德县',
+ 610827: '米脂县',
+ 610828: '佳县',
+ 610829: '吴堡县',
+ 610830: '清涧县',
+ 610831: '子洲县',
+ 610832: '其它区',
+ 610900: '安康市',
+ 610902: '汉滨区',
+ 610921: '汉阴县',
+ 610922: '石泉县',
+ 610923: '宁陕县',
+ 610924: '紫阳县',
+ 610925: '岚皋县',
+ 610926: '平利县',
+ 610927: '镇坪县',
+ 610928: '旬阳县',
+ 610929: '白河县',
+ 610930: '其它区',
+ 611000: '商洛市',
+ 611002: '商州区',
+ 611021: '洛南县',
+ 611022: '丹凤县',
+ 611023: '商南县',
+ 611024: '山阳县',
+ 611025: '镇安县',
+ 611026: '柞水县',
+ 611027: '其它区',
+ 620000: '甘肃省',
+ 620100: '兰州市',
+ 620102: '城关区',
+ 620103: '七里河区',
+ 620104: '西固区',
+ 620105: '安宁区',
+ 620111: '红古区',
+ 620121: '永登县',
+ 620122: '皋兰县',
+ 620123: '榆中县',
+ 620124: '其它区',
+ 620200: '嘉峪关市',
+ 620300: '金昌市',
+ 620302: '金川区',
+ 620321: '永昌县',
+ 620322: '其它区',
+ 620400: '白银市',
+ 620402: '白银区',
+ 620403: '平川区',
+ 620421: '靖远县',
+ 620422: '会宁县',
+ 620423: '景泰县',
+ 620424: '其它区',
+ 620500: '天水市',
+ 620502: '秦州区',
+ 620503: '麦积区',
+ 620521: '清水县',
+ 620522: '秦安县',
+ 620523: '甘谷县',
+ 620524: '武山县',
+ 620525: '张家川回族自治县',
+ 620526: '其它区',
+ 620600: '武威市',
+ 620602: '凉州区',
+ 620621: '民勤县',
+ 620622: '古浪县',
+ 620623: '天祝藏族自治县',
+ 620624: '其它区',
+ 620700: '张掖市',
+ 620702: '甘州区',
+ 620721: '肃南裕固族自治县',
+ 620722: '民乐县',
+ 620723: '临泽县',
+ 620724: '高台县',
+ 620725: '山丹县',
+ 620726: '其它区',
+ 620800: '平凉市',
+ 620802: '崆峒区',
+ 620821: '泾川县',
+ 620822: '灵台县',
+ 620823: '崇信县',
+ 620824: '华亭县',
+ 620825: '庄浪县',
+ 620826: '静宁县',
+ 620827: '其它区',
+ 620900: '酒泉市',
+ 620902: '肃州区',
+ 620921: '金塔县',
+ 620922: '瓜州县',
+ 620923: '肃北蒙古族自治县',
+ 620924: '阿克塞哈萨克族自治县',
+ 620981: '玉门市',
+ 620982: '敦煌市',
+ 620983: '其它区',
+ 621000: '庆阳市',
+ 621002: '西峰区',
+ 621021: '庆城县',
+ 621022: '环县',
+ 621023: '华池县',
+ 621024: '合水县',
+ 621025: '正宁县',
+ 621026: '宁县',
+ 621027: '镇原县',
+ 621028: '其它区',
+ 621100: '定西市',
+ 621102: '安定区',
+ 621121: '通渭县',
+ 621122: '陇西县',
+ 621123: '渭源县',
+ 621124: '临洮县',
+ 621125: '漳县',
+ 621126: '岷县',
+ 621127: '其它区',
+ 621200: '陇南市',
+ 621202: '武都区',
+ 621221: '成县',
+ 621222: '文县',
+ 621223: '宕昌县',
+ 621224: '康县',
+ 621225: '西和县',
+ 621226: '礼县',
+ 621227: '徽县',
+ 621228: '两当县',
+ 621229: '其它区',
+ 622900: '临夏回族自治州',
+ 622901: '临夏市',
+ 622921: '临夏县',
+ 622922: '康乐县',
+ 622923: '永靖县',
+ 622924: '广河县',
+ 622925: '和政县',
+ 622926: '东乡族自治县',
+ 622927: '积石山保安族东乡族撒拉族自治县',
+ 622928: '其它区',
+ 623000: '甘南藏族自治州',
+ 623001: '合作市',
+ 623021: '临潭县',
+ 623022: '卓尼县',
+ 623023: '舟曲县',
+ 623024: '迭部县',
+ 623025: '玛曲县',
+ 623026: '碌曲县',
+ 623027: '夏河县',
+ 623028: '其它区',
+ 630000: '青海省',
+ 630100: '西宁市',
+ 630102: '城东区',
+ 630103: '城中区',
+ 630104: '城西区',
+ 630105: '城北区',
+ 630121: '大通回族土族自治县',
+ 630122: '湟中县',
+ 630123: '湟源县',
+ 630124: '其它区',
+ 632100: '海东市',
+ 632121: '平安县',
+ 632122: '民和回族土族自治县',
+ 632123: '乐都区',
+ 632126: '互助土族自治县',
+ 632127: '化隆回族自治县',
+ 632128: '循化撒拉族自治县',
+ 632129: '其它区',
+ 632200: '海北藏族自治州',
+ 632221: '门源回族自治县',
+ 632222: '祁连县',
+ 632223: '海晏县',
+ 632224: '刚察县',
+ 632225: '其它区',
+ 632300: '黄南藏族自治州',
+ 632321: '同仁县',
+ 632322: '尖扎县',
+ 632323: '泽库县',
+ 632324: '河南蒙古族自治县',
+ 632325: '其它区',
+ 632500: '海南藏族自治州',
+ 632521: '共和县',
+ 632522: '同德县',
+ 632523: '贵德县',
+ 632524: '兴海县',
+ 632525: '贵南县',
+ 632526: '其它区',
+ 632600: '果洛藏族自治州',
+ 632621: '玛沁县',
+ 632622: '班玛县',
+ 632623: '甘德县',
+ 632624: '达日县',
+ 632625: '久治县',
+ 632626: '玛多县',
+ 632627: '其它区',
+ 632700: '玉树藏族自治州',
+ 632721: '玉树市',
+ 632722: '杂多县',
+ 632723: '称多县',
+ 632724: '治多县',
+ 632725: '囊谦县',
+ 632726: '曲麻莱县',
+ 632727: '其它区',
+ 632800: '海西蒙古族藏族自治州',
+ 632801: '格尔木市',
+ 632802: '德令哈市',
+ 632821: '乌兰县',
+ 632822: '都兰县',
+ 632823: '天峻县',
+ 632824: '其它区',
+ 640000: '宁夏回族自治区',
+ 640100: '银川市',
+ 640104: '兴庆区',
+ 640105: '西夏区',
+ 640106: '金凤区',
+ 640121: '永宁县',
+ 640122: '贺兰县',
+ 640181: '灵武市',
+ 640182: '其它区',
+ 640200: '石嘴山市',
+ 640202: '大武口区',
+ 640205: '惠农区',
+ 640221: '平罗县',
+ 640222: '其它区',
+ 640300: '吴忠市',
+ 640302: '利通区',
+ 640303: '红寺堡区',
+ 640323: '盐池县',
+ 640324: '同心县',
+ 640381: '青铜峡市',
+ 640382: '其它区',
+ 640400: '固原市',
+ 640402: '原州区',
+ 640422: '西吉县',
+ 640423: '隆德县',
+ 640424: '泾源县',
+ 640425: '彭阳县',
+ 640426: '其它区',
+ 640500: '中卫市',
+ 640502: '沙坡头区',
+ 640521: '中宁县',
+ 640522: '海原县',
+ 640523: '其它区',
+ 650000: '新疆维吾尔自治区',
+ 650100: '乌鲁木齐市',
+ 650102: '天山区',
+ 650103: '沙依巴克区',
+ 650104: '新市区',
+ 650105: '水磨沟区',
+ 650106: '头屯河区',
+ 650107: '达坂城区',
+ 650109: '米东区',
+ 650121: '乌鲁木齐县',
+ 650122: '其它区',
+ 650200: '克拉玛依市',
+ 650202: '独山子区',
+ 650203: '克拉玛依区',
+ 650204: '白碱滩区',
+ 650205: '乌尔禾区',
+ 650206: '其它区',
+ 652100: '吐鲁番地区',
+ 652101: '吐鲁番市',
+ 652122: '鄯善县',
+ 652123: '托克逊县',
+ 652124: '其它区',
+ 652200: '哈密地区',
+ 652201: '哈密市',
+ 652222: '巴里坤哈萨克自治县',
+ 652223: '伊吾县',
+ 652224: '其它区',
+ 652300: '昌吉回族自治州',
+ 652301: '昌吉市',
+ 652302: '阜康市',
+ 652323: '呼图壁县',
+ 652324: '玛纳斯县',
+ 652325: '奇台县',
+ 652327: '吉木萨尔县',
+ 652328: '木垒哈萨克自治县',
+ 652329: '其它区',
+ 652700: '博尔塔拉蒙古自治州',
+ 652701: '博乐市',
+ 652702: '阿拉山口市',
+ 652722: '精河县',
+ 652723: '温泉县',
+ 652724: '其它区',
+ 652800: '巴音郭楞蒙古自治州',
+ 652801: '库尔勒市',
+ 652822: '轮台县',
+ 652823: '尉犁县',
+ 652824: '若羌县',
+ 652825: '且末县',
+ 652826: '焉耆回族自治县',
+ 652827: '和静县',
+ 652828: '和硕县',
+ 652829: '博湖县',
+ 652830: '其它区',
+ 652900: '阿克苏地区',
+ 652901: '阿克苏市',
+ 652922: '温宿县',
+ 652923: '库车县',
+ 652924: '沙雅县',
+ 652925: '新和县',
+ 652926: '拜城县',
+ 652927: '乌什县',
+ 652928: '阿瓦提县',
+ 652929: '柯坪县',
+ 652930: '其它区',
+ 653000: '克孜勒苏柯尔克孜自治州',
+ 653001: '阿图什市',
+ 653022: '阿克陶县',
+ 653023: '阿合奇县',
+ 653024: '乌恰县',
+ 653025: '其它区',
+ 653100: '喀什地区',
+ 653101: '喀什市',
+ 653121: '疏附县',
+ 653122: '疏勒县',
+ 653123: '英吉沙县',
+ 653124: '泽普县',
+ 653125: '莎车县',
+ 653126: '叶城县',
+ 653127: '麦盖提县',
+ 653128: '岳普湖县',
+ 653129: '伽师县',
+ 653130: '巴楚县',
+ 653131: '塔什库尔干塔吉克自治县',
+ 653132: '其它区',
+ 653200: '和田地区',
+ 653201: '和田市',
+ 653221: '和田县',
+ 653222: '墨玉县',
+ 653223: '皮山县',
+ 653224: '洛浦县',
+ 653225: '策勒县',
+ 653226: '于田县',
+ 653227: '民丰县',
+ 653228: '其它区',
+ 654000: '伊犁哈萨克自治州',
+ 654002: '伊宁市',
+ 654003: '奎屯市',
+ 654021: '伊宁县',
+ 654022: '察布查尔锡伯自治县',
+ 654023: '霍城县',
+ 654024: '巩留县',
+ 654025: '新源县',
+ 654026: '昭苏县',
+ 654027: '特克斯县',
+ 654028: '尼勒克县',
+ 654029: '其它区',
+ 654200: '塔城地区',
+ 654201: '塔城市',
+ 654202: '乌苏市',
+ 654221: '额敏县',
+ 654223: '沙湾县',
+ 654224: '托里县',
+ 654225: '裕民县',
+ 654226: '和布克赛尔蒙古自治县',
+ 654227: '其它区',
+ 654300: '阿勒泰地区',
+ 654301: '阿勒泰市',
+ 654321: '布尔津县',
+ 654322: '富蕴县',
+ 654323: '福海县',
+ 654324: '哈巴河县',
+ 654325: '青河县',
+ 654326: '吉木乃县',
+ 654327: '其它区',
+ 659001: '石河子市',
+ 659002: '阿拉尔市',
+ 659003: '图木舒克市',
+ 659004: '五家渠市',
+ 710000: '台湾',
+ 710100: '台北市',
+ 710101: '中正区',
+ 710102: '大同区',
+ 710103: '中山区',
+ 710104: '松山区',
+ 710105: '大安区',
+ 710106: '万华区',
+ 710107: '信义区',
+ 710108: '士林区',
+ 710109: '北投区',
+ 710110: '内湖区',
+ 710111: '南港区',
+ 710112: '文山区',
+ 710113: '其它区',
+ 710200: '高雄市',
+ 710201: '新兴区',
+ 710202: '前金区',
+ 710203: '芩雅区',
+ 710204: '盐埕区',
+ 710205: '鼓山区',
+ 710206: '旗津区',
+ 710207: '前镇区',
+ 710208: '三民区',
+ 710209: '左营区',
+ 710210: '楠梓区',
+ 710211: '小港区',
+ 710212: '其它区',
+ 710241: '苓雅区',
+ 710242: '仁武区',
+ 710243: '大社区',
+ 710244: '冈山区',
+ 710245: '路竹区',
+ 710246: '阿莲区',
+ 710247: '田寮区',
+ 710248: '燕巢区',
+ 710249: '桥头区',
+ 710250: '梓官区',
+ 710251: '弥陀区',
+ 710252: '永安区',
+ 710253: '湖内区',
+ 710254: '凤山区',
+ 710255: '大寮区',
+ 710256: '林园区',
+ 710257: '鸟松区',
+ 710258: '大树区',
+ 710259: '旗山区',
+ 710260: '美浓区',
+ 710261: '六龟区',
+ 710262: '内门区',
+ 710263: '杉林区',
+ 710264: '甲仙区',
+ 710265: '桃源区',
+ 710266: '那玛夏区',
+ 710267: '茂林区',
+ 710268: '茄萣区',
+ 710300: '台南市',
+ 710301: '中西区',
+ 710302: '东区',
+ 710303: '南区',
+ 710304: '北区',
+ 710305: '安平区',
+ 710306: '安南区',
+ 710307: '其它区',
+ 710339: '永康区',
+ 710340: '归仁区',
+ 710341: '新化区',
+ 710342: '左镇区',
+ 710343: '玉井区',
+ 710344: '楠西区',
+ 710345: '南化区',
+ 710346: '仁德区',
+ 710347: '关庙区',
+ 710348: '龙崎区',
+ 710349: '官田区',
+ 710350: '麻豆区',
+ 710351: '佳里区',
+ 710352: '西港区',
+ 710353: '七股区',
+ 710354: '将军区',
+ 710355: '学甲区',
+ 710356: '北门区',
+ 710357: '新营区',
+ 710358: '后壁区',
+ 710359: '白河区',
+ 710360: '东山区',
+ 710361: '六甲区',
+ 710362: '下营区',
+ 710363: '柳营区',
+ 710364: '盐水区',
+ 710365: '善化区',
+ 710366: '大内区',
+ 710367: '山上区',
+ 710368: '新市区',
+ 710369: '安定区',
+ 710400: '台中市',
+ 710401: '中区',
+ 710402: '东区',
+ 710403: '南区',
+ 710404: '西区',
+ 710405: '北区',
+ 710406: '北屯区',
+ 710407: '西屯区',
+ 710408: '南屯区',
+ 710409: '其它区',
+ 710431: '太平区',
+ 710432: '大里区',
+ 710433: '雾峰区',
+ 710434: '乌日区',
+ 710435: '丰原区',
+ 710436: '后里区',
+ 710437: '石冈区',
+ 710438: '东势区',
+ 710439: '和平区',
+ 710440: '新社区',
+ 710441: '潭子区',
+ 710442: '大雅区',
+ 710443: '神冈区',
+ 710444: '大肚区',
+ 710445: '沙鹿区',
+ 710446: '龙井区',
+ 710447: '梧栖区',
+ 710448: '清水区',
+ 710449: '大甲区',
+ 710450: '外埔区',
+ 710451: '大安区',
+ 710500: '金门县',
+ 710507: '金沙镇',
+ 710508: '金湖镇',
+ 710509: '金宁乡',
+ 710510: '金城镇',
+ 710511: '烈屿乡',
+ 710512: '乌坵乡',
+ 710600: '南投县',
+ 710614: '南投市',
+ 710615: '中寮乡',
+ 710616: '草屯镇',
+ 710617: '国姓乡',
+ 710618: '埔里镇',
+ 710619: '仁爱乡',
+ 710620: '名间乡',
+ 710621: '集集镇',
+ 710622: '水里乡',
+ 710623: '鱼池乡',
+ 710624: '信义乡',
+ 710625: '竹山镇',
+ 710626: '鹿谷乡',
+ 710700: '基隆市',
+ 710701: '仁爱区',
+ 710702: '信义区',
+ 710703: '中正区',
+ 710704: '中山区',
+ 710705: '安乐区',
+ 710706: '暖暖区',
+ 710707: '七堵区',
+ 710708: '其它区',
+ 710800: '新竹市',
+ 710801: '东区',
+ 710802: '北区',
+ 710803: '香山区',
+ 710804: '其它区',
+ 710900: '嘉义市',
+ 710901: '东区',
+ 710902: '西区',
+ 710903: '其它区',
+ 711100: '新北市',
+ 711130: '万里区',
+ 711131: '金山区',
+ 711132: '板桥区',
+ 711133: '汐止区',
+ 711134: '深坑区',
+ 711135: '石碇区',
+ 711136: '瑞芳区',
+ 711137: '平溪区',
+ 711138: '双溪区',
+ 711139: '贡寮区',
+ 711140: '新店区',
+ 711141: '坪林区',
+ 711142: '乌来区',
+ 711143: '永和区',
+ 711144: '中和区',
+ 711145: '土城区',
+ 711146: '三峡区',
+ 711147: '树林区',
+ 711148: '莺歌区',
+ 711149: '三重区',
+ 711150: '新庄区',
+ 711151: '泰山区',
+ 711152: '林口区',
+ 711153: '芦洲区',
+ 711154: '五股区',
+ 711155: '八里区',
+ 711156: '淡水区',
+ 711157: '三芝区',
+ 711158: '石门区',
+ 711200: '宜兰县',
+ 711214: '宜兰市',
+ 711215: '头城镇',
+ 711216: '礁溪乡',
+ 711217: '壮围乡',
+ 711218: '员山乡',
+ 711219: '罗东镇',
+ 711220: '三星乡',
+ 711221: '大同乡',
+ 711222: '五结乡',
+ 711223: '冬山乡',
+ 711224: '苏澳镇',
+ 711225: '南澳乡',
+ 711226: '钓鱼台',
+ 711300: '新竹县',
+ 711314: '竹北市',
+ 711315: '湖口乡',
+ 711316: '新丰乡',
+ 711317: '新埔镇',
+ 711318: '关西镇',
+ 711319: '芎林乡',
+ 711320: '宝山乡',
+ 711321: '竹东镇',
+ 711322: '五峰乡',
+ 711323: '横山乡',
+ 711324: '尖石乡',
+ 711325: '北埔乡',
+ 711326: '峨眉乡',
+ 711400: '桃园县',
+ 711414: '中坜市',
+ 711415: '平镇市',
+ 711416: '龙潭乡',
+ 711417: '杨梅市',
+ 711418: '新屋乡',
+ 711419: '观音乡',
+ 711420: '桃园市',
+ 711421: '龟山乡',
+ 711422: '八德市',
+ 711423: '大溪镇',
+ 711424: '复兴乡',
+ 711425: '大园乡',
+ 711426: '芦竹乡',
+ 711500: '苗栗县',
+ 711519: '竹南镇',
+ 711520: '头份镇',
+ 711521: '三湾乡',
+ 711522: '南庄乡',
+ 711523: '狮潭乡',
+ 711524: '后龙镇',
+ 711525: '通霄镇',
+ 711526: '苑里镇',
+ 711527: '苗栗市',
+ 711528: '造桥乡',
+ 711529: '头屋乡',
+ 711530: '公馆乡',
+ 711531: '大湖乡',
+ 711532: '泰安乡',
+ 711533: '铜锣乡',
+ 711534: '三义乡',
+ 711535: '西湖乡',
+ 711536: '卓兰镇',
+ 711700: '彰化县',
+ 711727: '彰化市',
+ 711728: '芬园乡',
+ 711729: '花坛乡',
+ 711730: '秀水乡',
+ 711731: '鹿港镇',
+ 711732: '福兴乡',
+ 711733: '线西乡',
+ 711734: '和美镇',
+ 711735: '伸港乡',
+ 711736: '员林镇',
+ 711737: '社头乡',
+ 711738: '永靖乡',
+ 711739: '埔心乡',
+ 711740: '溪湖镇',
+ 711741: '大村乡',
+ 711742: '埔盐乡',
+ 711743: '田中镇',
+ 711744: '北斗镇',
+ 711745: '田尾乡',
+ 711746: '埤头乡',
+ 711747: '溪州乡',
+ 711748: '竹塘乡',
+ 711749: '二林镇',
+ 711750: '大城乡',
+ 711751: '芳苑乡',
+ 711752: '二水乡',
+ 711900: '嘉义县',
+ 711919: '番路乡',
+ 711920: '梅山乡',
+ 711921: '竹崎乡',
+ 711922: '阿里山乡',
+ 711923: '中埔乡',
+ 711924: '大埔乡',
+ 711925: '水上乡',
+ 711926: '鹿草乡',
+ 711927: '太保市',
+ 711928: '朴子市',
+ 711929: '东石乡',
+ 711930: '六脚乡',
+ 711931: '新港乡',
+ 711932: '民雄乡',
+ 711933: '大林镇',
+ 711934: '溪口乡',
+ 711935: '义竹乡',
+ 711936: '布袋镇',
+ 712100: '云林县',
+ 712121: '斗南镇',
+ 712122: '大埤乡',
+ 712123: '虎尾镇',
+ 712124: '土库镇',
+ 712125: '褒忠乡',
+ 712126: '东势乡',
+ 712127: '台西乡',
+ 712128: '仑背乡',
+ 712129: '麦寮乡',
+ 712130: '斗六市',
+ 712131: '林内乡',
+ 712132: '古坑乡',
+ 712133: '莿桐乡',
+ 712134: '西螺镇',
+ 712135: '二仑乡',
+ 712136: '北港镇',
+ 712137: '水林乡',
+ 712138: '口湖乡',
+ 712139: '四湖乡',
+ 712140: '元长乡',
+ 712400: '屏东县',
+ 712434: '屏东市',
+ 712435: '三地门乡',
+ 712436: '雾台乡',
+ 712437: '玛家乡',
+ 712438: '九如乡',
+ 712439: '里港乡',
+ 712440: '高树乡',
+ 712441: '盐埔乡',
+ 712442: '长治乡',
+ 712443: '麟洛乡',
+ 712444: '竹田乡',
+ 712445: '内埔乡',
+ 712446: '万丹乡',
+ 712447: '潮州镇',
+ 712448: '泰武乡',
+ 712449: '来义乡',
+ 712450: '万峦乡',
+ 712451: '崁顶乡',
+ 712452: '新埤乡',
+ 712453: '南州乡',
+ 712454: '林边乡',
+ 712455: '东港镇',
+ 712456: '琉球乡',
+ 712457: '佳冬乡',
+ 712458: '新园乡',
+ 712459: '枋寮乡',
+ 712460: '枋山乡',
+ 712461: '春日乡',
+ 712462: '狮子乡',
+ 712463: '车城乡',
+ 712464: '牡丹乡',
+ 712465: '恒春镇',
+ 712466: '满州乡',
+ 712500: '台东县',
+ 712517: '台东市',
+ 712518: '绿岛乡',
+ 712519: '兰屿乡',
+ 712520: '延平乡',
+ 712521: '卑南乡',
+ 712522: '鹿野乡',
+ 712523: '关山镇',
+ 712524: '海端乡',
+ 712525: '池上乡',
+ 712526: '东河乡',
+ 712527: '成功镇',
+ 712528: '长滨乡',
+ 712529: '金峰乡',
+ 712530: '大武乡',
+ 712531: '达仁乡',
+ 712532: '太麻里乡',
+ 712600: '花莲县',
+ 712615: '花莲市',
+ 712616: '新城乡',
+ 712617: '太鲁阁',
+ 712618: '秀林乡',
+ 712619: '吉安乡',
+ 712620: '寿丰乡',
+ 712621: '凤林镇',
+ 712622: '光复乡',
+ 712623: '丰滨乡',
+ 712624: '瑞穗乡',
+ 712625: '万荣乡',
+ 712626: '玉里镇',
+ 712627: '卓溪乡',
+ 712628: '富里乡',
+ 712700: '澎湖县',
+ 712707: '马公市',
+ 712708: '西屿乡',
+ 712709: '望安乡',
+ 712710: '七美乡',
+ 712711: '白沙乡',
+ 712712: '湖西乡',
+ 712800: '连江县',
+ 712805: '南竿乡',
+ 712806: '北竿乡',
+ 712807: '莒光乡',
+ 712808: '东引乡',
+ 810000: '香港特别行政区',
+ 810100: '香港岛',
+ 810101: '中西区',
+ 810102: '湾仔',
+ 810103: '东区',
+ 810104: '南区',
+ 810200: '九龙',
+ 810201: '九龙城区',
+ 810202: '油尖旺区',
+ 810203: '深水埗区',
+ 810204: '黄大仙区',
+ 810205: '观塘区',
+ 810300: '新界',
+ 810301: '北区',
+ 810302: '大埔区',
+ 810303: '沙田区',
+ 810304: '西贡区',
+ 810305: '元朗区',
+ 810306: '屯门区',
+ 810307: '荃湾区',
+ 810308: '葵青区',
+ 810309: '离岛区',
+ 820000: '澳门特别行政区',
+ 820100: '澳门半岛',
+ 820200: '离岛',
+ 990000: '海外',
+ 990100: '海外',
+};
+
+const tree = list => {
+ let hashTable = Object.create(null);
+ list.forEach(aData => (hashTable[aData.id] = { ...aData, children: [] }));
+ let dataTree = [];
+ list.forEach(aData => {
+ if (aData.pid) {
+ if (hashTable[aData.pid]) hashTable[aData.pid].children.push(hashTable[aData.id]);
+ } else dataTree.push(hashTable[aData.id]);
+ });
+ return dataTree;
+};
+
+let DICT_FIXED = (function () {
+ let fixed = [];
+ for (let id in DICT) {
+ if ({}.hasOwnProperty.call(DICT, id)) {
+ let pid;
+ const tmpObj = { id, value: DICT[id], label: DICT[id] };
+ if (id.slice(2, 6) !== '0000') {
+ pid = id.slice(4, 6) === '00' ? `${id.slice(0, 2)}0000` : `${id.slice(0, 4)}00`;
+ }
+ if (pid) tmpObj.pid = pid;
+ fixed.push(tmpObj);
+ }
+ }
+ return tree(fixed);
+})();
+
+export default DICT_FIXED;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/config.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/config.js
new file mode 100644
index 00000000..24f8d999
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/config.js
@@ -0,0 +1,41 @@
+const config = {
+ siteName: 'inula Antd',
+ copyright: 'Ant Design Admin ©2020 zuiidea',
+ logoPath: '/logo.svg',
+ apiPrefix: '/api/v1',
+ fixedHeader: true, // sticky primary layout header
+
+ /* Layout configuration, specify which layout to use for route. */
+ layouts: [
+ {
+ name: 'primary',
+ include: [/.*/],
+ exclude: [/(\/(en|zh))*\/login/],
+ },
+ ],
+
+ /* I18n configuration, `languages` and `defaultLanguage` are required currently. */
+ i18n: {
+ /* Countrys flags: https://www.flaticon.com/packs/countrys-flags */
+ languages: [
+ {
+ key: 'pt-br',
+ title: 'Português',
+ flag: '/portugal.svg',
+ },
+ {
+ key: 'en',
+ title: 'English',
+ flag: '/america.svg',
+ },
+ {
+ key: 'zh',
+ title: '中文',
+ flag: '/china.svg',
+ },
+ ],
+ defaultLanguage: 'en',
+ },
+};
+
+export default config;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/constant.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/constant.js
new file mode 100644
index 00000000..80b0b7ed
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/constant.js
@@ -0,0 +1,7 @@
+export const ROLE_TYPE = {
+ ADMIN: 'admin',
+ DEFAULT: 'admin',
+ DEVELOPER: 'developer',
+};
+
+export const CANCEL_REQUEST_MESSAGE = 'cancel request';
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/iconMap.jsx b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/iconMap.jsx
new file mode 100644
index 00000000..991c5c20
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/iconMap.jsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import {
+ PayCircleOutlined,
+ ShoppingCartOutlined,
+ MessageOutlined,
+ TeamOutlined,
+ UserOutlined,
+ DashboardOutlined,
+ ApiOutlined,
+ CameraOutlined,
+ EditOutlined,
+ CodeOutlined,
+ LineOutlined,
+ BarChartOutlined,
+ AreaChartOutlined,
+} from '@ant-design/icons';
+
+export default {
+ 'pay-circle-o': ,
+ 'shopping-cart': ,
+ 'camera-o': ,
+ 'line-chart': ,
+ 'code-o': ,
+ 'area-chart': ,
+ 'bar-chart': ,
+ message: ,
+ team: ,
+ dashboard: ,
+ user: ,
+ api: ,
+ edit: ,
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/index.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/index.js
new file mode 100644
index 00000000..a676d9c6
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/index.js
@@ -0,0 +1,168 @@
+import { cloneDeep } from 'lodash';
+import { pathToRegexp } from 'path-to-regexp';
+import moment from 'moment';
+import 'moment/locale/zh-cn';
+import store from 'store';
+import config from './config';
+
+// export classnames from 'classnames'
+// export config from './config'
+// export request from './request'
+// export { Color } from './theme'
+
+export const languages = config.i18n ? config.i18n.languages.map(item => item.key) : [];
+export const defaultLanguage = config.i18n ? config.i18n.defaultLanguage : '';
+
+/**
+ * Query objects that specify keys and values in an array where all values are objects.
+ * @param {array} array An array where all values are objects, like [{key:1},{key:2}].
+ * @param {string} key The key of the object that needs to be queried.
+ * @param {string} value The value of the object that needs to be queried.
+ * @return {object|undefined} Return frist object when query success.
+ */
+export function queryArray(array, key, value) {
+ if (!Array.isArray(array)) {
+ return;
+ }
+ return array.find(_ => _[key] === value);
+}
+
+/**
+ * Convert an array to a tree-structured array.
+ * @param {array} array The Array need to Converted.
+ * @param {string} id The alias of the unique ID of the object in the array.
+ * @param {string} parentId The alias of the parent ID of the object in the array.
+ * @param {string} children The alias of children of the object in the array.
+ * @return {array} Return a tree-structured array.
+ */
+export function arrayToTree(array, id = 'id', parentId = 'pid', children = 'children') {
+ const result = [];
+ const hash = {};
+ const data = cloneDeep(array);
+
+ data.forEach((item, index) => {
+ hash[data[index][id]] = data[index];
+ });
+
+ data.forEach(item => {
+ const hashParent = hash[item[parentId]];
+ if (hashParent) {
+ !hashParent[children] && (hashParent[children] = []);
+ hashParent[children].push(item);
+ } else {
+ result.push(item);
+ }
+ });
+ return result;
+}
+
+/**
+ * In an array object, traverse all parent IDs based on the value of an object.
+ * @param {array} array The Array need to Converted.
+ * @param {string} current Specify the value of the object that needs to be queried.
+ * @param {string} parentId The alias of the parent ID of the object in the array.
+ * @param {string} id The alias of the unique ID of the object in the array.
+ * @return {array} Return a key array.
+ */
+export function queryPathKeys(array, current, parentId, id = 'id') {
+ const result = [current];
+ const hashMap = new Map();
+ array.forEach(item => hashMap.set(item[id], item));
+
+ const getPath = current => {
+ const currentParentId = hashMap.get(current)[parentId];
+ if (currentParentId) {
+ result.push(currentParentId);
+ getPath(currentParentId);
+ }
+ };
+
+ getPath(current);
+ return result;
+}
+
+/**
+ * In an array of objects, specify an object that traverses the objects whose parent ID matches.
+ * @param {array} array The Array need to Converted.
+ * @param {string} current Specify the object that needs to be queried.
+ * @param {string} parentId The alias of the parent ID of the object in the array.
+ * @param {string} id The alias of the unique ID of the object in the array.
+ * @return {array} Return a key array.
+ */
+export function queryAncestors(array, current, parentId, id = 'id') {
+ const result = [current];
+ const hashMap = new Map();
+ array.forEach(item => hashMap.set(item[id], item));
+
+ const getPath = current => {
+ const currentParentId = hashMap.get(current[id])[parentId];
+ if (currentParentId) {
+ result.push(hashMap.get(currentParentId));
+ getPath(hashMap.get(currentParentId));
+ }
+ };
+
+ getPath(current);
+ return result;
+}
+
+/**
+ * Query which layout should be used for the current path based on the configuration.
+ * @param {layouts} layouts Layout configuration.
+ * @param {pathname} pathname Path name to be queried.
+ * @return {string} Return frist object when query success.
+ */
+export function queryLayout(layouts, pathname) {
+ let result = 'public';
+
+ const isMatch = regepx => {
+ return regepx instanceof RegExp ? regepx.test(pathname) : pathToRegexp(regepx).exec(pathname);
+ };
+
+ for (const item of layouts) {
+ let include = false;
+ let exclude = false;
+ if (item.include) {
+ for (const regepx of item.include) {
+ if (isMatch(regepx)) {
+ include = true;
+ break;
+ }
+ }
+ }
+
+ if (include && item.exclude) {
+ for (const regepx of item.exclude) {
+ if (isMatch(regepx)) {
+ exclude = true;
+ break;
+ }
+ }
+ }
+
+ if (include && !exclude) {
+ result = item.name;
+ break;
+ }
+ }
+
+ return result;
+}
+
+export function getLocale() {
+ return store.get('locale') || defaultLanguage;
+}
+
+export function setLocale(language) {
+ if (getLocale() !== language) {
+ moment.locale(language === 'zh' ? 'zh-cn' : language);
+ store.set('locale', language);
+ window.location.reload();
+ }
+}
+
+export function parseSearch(search) {
+ const searchObj = {};
+ search.replace(/([^?&=]+)=([^&]+)/g, (_, k, v) => (searchObj[k] = decodeURI(v)));
+ return searchObj;
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/index.test.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/index.test.js
new file mode 100644
index 00000000..b13551eb
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/index.test.js
@@ -0,0 +1,11 @@
+const { pathToRegexp } = require('path-to-regexp');
+
+describe('test pathToRegexp', () => {
+ it('get right', () => {
+ expect(pathToRegexp('/user').exec('/zh/user')).toEqual(pathToRegexp('/user').exec('/user'));
+ expect(pathToRegexp('/user').exec('/user')).toEqual(pathToRegexp('/user').exec('/user'));
+
+ expect(pathToRegexp('/user/:id').exec('/zh/user/1')).toEqual(pathToRegexp('/user/:id').exec('/user/1'));
+ expect(pathToRegexp('/user/:id').exec('/user/1')).toEqual(pathToRegexp('/user/:id').exec('/user/1'));
+ });
+});
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/intl.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/intl.js
new file mode 100644
index 00000000..72f3396c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/intl.js
@@ -0,0 +1,55 @@
+/**
+ * 国际化,支持按需加载
+ */
+
+import React from 'react';
+import { createIntl, createIntlCache, FormattedMessage } from 'react-intl';
+import zhCN from 'antd/lib/locale-provider/zh_CN';
+import enUS from 'antd/lib/locale-provider/en_US';
+import ptBR from 'antd/lib/locale-provider/pt_BR';
+
+import enMessage from '@/locales/en/messages';
+import zhMessage from '@/locales/zh/messages';
+import ptMessage from '@/locales/pt-br/messages';
+
+const _langResource = {
+ zh: { ...zhCN, ...zhMessage },
+ en: { ...enUS, ...enMessage },
+ 'pt-br': { ...ptBR, ...ptMessage },
+};
+
+let _intl = null;
+
+export const getLangResource = lan => {
+ if (!_intl) {
+ _intl = createIntl({ locale: lan, messages: _langResource[lan] }, createIntlCache());
+ }
+
+ return _langResource;
+};
+
+export const loadLangResource = async lan => {
+ if (!_intl) {
+ _intl = createIntl({ locale: lan, messages: _langResource[lan] }, createIntlCache());
+ }
+
+ const messages = await import(`@/locales/${lan}/messages`);
+
+ Object.keys(messages.default).forEach(key => {
+ _langResource[lan][key] = messages.default[key];
+ });
+
+ Object.assign(_intl.messages, _langResource[lan]);
+};
+
+export const t = (key, values) => {
+ if (!key) {
+ return;
+ }
+
+ return _intl.formatMessage({ id: key }, values) || key;
+};
+
+export const Trans = ({ children }) => {
+ return ;
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/request.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/request.js
new file mode 100644
index 00000000..48e1139d
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/request.js
@@ -0,0 +1,96 @@
+import axios from 'axios';
+import { cloneDeep } from 'lodash';
+
+import { parse, compile } from 'path-to-regexp';
+import { message } from 'antd';
+import { CANCEL_REQUEST_MESSAGE } from 'utils/constant';
+
+const { CancelToken } = axios;
+window.cancelRequest = new Map();
+
+export default function request(options) {
+ let { data, url } = options;
+ const cloneData = cloneDeep(data);
+
+ try {
+ let domain = '';
+ const urlMatch = url.match(/[a-zA-z]+:\/\/[^/]*/);
+ if (urlMatch) {
+ [domain] = urlMatch;
+ url = url.slice(domain.length);
+ }
+
+ const match = parse(url);
+ url = compile(url)(data);
+
+ for (const item of match) {
+ if (item instanceof Object && item.name in cloneData) {
+ delete cloneData[item.name];
+ }
+ }
+ url = domain + url;
+ } catch (e) {
+ message.error(e.message);
+ }
+
+ options.url = url;
+ options.cancelToken = new CancelToken(cancel => {
+ window.cancelRequest.set(Symbol(Date.now()), {
+ pathname: window.location.pathname,
+ cancel,
+ });
+ });
+
+ options.params = options.data;
+
+ return axios(options)
+ .then(response => {
+ const { statusText, status, data } = response;
+
+ let result = {};
+ if (typeof data === 'object') {
+ if (Array.isArray(data)) {
+ result.list = data;
+ } else {
+ result = data;
+ }
+ } else {
+ result.data = data;
+ }
+
+ return Promise.resolve({
+ success: true,
+ message: statusText,
+ statusCode: status,
+ ...result,
+ });
+ })
+ .catch(error => {
+ const { response, message } = error;
+
+ if (String(message) === CANCEL_REQUEST_MESSAGE) {
+ return {
+ success: false,
+ };
+ }
+
+ let msg;
+ let statusCode;
+
+ if (response && response instanceof Object) {
+ const { data, statusText } = response;
+ statusCode = response.status;
+ msg = data.message || statusText;
+ } else {
+ statusCode = 600;
+ msg = error.message || 'Network Error';
+ }
+
+ /* eslint-disable */
+ return Promise.reject({
+ success: false,
+ statusCode,
+ message: msg,
+ });
+ });
+}
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/theme.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/theme.js
new file mode 100644
index 00000000..18b7728c
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/src/admin/utils/theme.js
@@ -0,0 +1,29 @@
+// module.exports = {
+// Color: {
+// green: '#64ea91',
+// blue: '#8fc9fb',
+// purple: '#d897eb',
+// red: '#f69899',
+// yellow: '#f8c82e',
+// peach: '#f797d6',
+// borderBase: '#e5e5e5',
+// borderSplit: '#f4f4f4',
+// grass: '#d6fbb5',
+// sky: '#c1e0fc',
+// },
+// }
+
+const Color = {
+ green: '#64ea91',
+ blue: '#8fc9fb',
+ purple: '#d897eb',
+ red: '#f69899',
+ yellow: '#f8c82e',
+ peach: '#f797d6',
+ borderBase: '#e5e5e5',
+ borderSplit: '#f4f4f4',
+ grass: '#d6fbb5',
+ sky: '#c1e0fc',
+};
+
+export default Color;
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/vite.config.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/vite.config.js
new file mode 100644
index 00000000..bdba1810
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/vite/vite.config.js
@@ -0,0 +1,57 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import path from 'path';
+import { viteMockServe } from 'vite-plugin-mock';
+// import requireTransform from 'vite-plugin-require-transform';
+
+let alias = {
+ '@': path.resolve('src/admin'),
+ api: path.resolve('src/admin/services/'),
+ components: path.resolve('src/admin/components'),
+ config: path.resolve('src/admin/utils/config'),
+ themes: path.resolve('src/admin/themes'),
+ utils: path.resolve('src/admin/utils'),
+ react: 'inula', // 新增
+ 'react-dom': 'inula', // 新增
+ 'react/jsx-dev-runtime': 'inula/jsx-dev-runtime',
+};
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ react({
+ babel: {
+ plugins: [
+ '@babel/plugin-transform-react-jsx',
+ '@babel/plugin-proposal-class-properties',
+ '@babel/plugin-syntax-dynamic-import',
+ '@babel/plugin-proposal-export-default-from',
+ ],
+ },
+ }),
+ viteMockServe({
+ mockPath: './mock',
+ }),
+ ],
+ define: {
+ global: 'window',
+ },
+ resolve: {
+ alias,
+ },
+ optimizeDeps: {
+ esbuildOptions: {
+ loader: {
+ '.js': 'jsx',
+ '.ts': 'tsx',
+ },
+ },
+ },
+ css: {
+ preprocessorOptions: {
+ less: {
+ javascriptEnabled: true,
+ },
+ },
+ },
+});
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.editorconfig b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.editorconfig
new file mode 100644
index 00000000..5a51806d
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.editorconfig
@@ -0,0 +1,10 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_size = 2
+indent_style = space
+trim_trailing_whitespace = true
+
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.env b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.env
new file mode 100644
index 00000000..6c5aec02
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.env
@@ -0,0 +1,4 @@
+PROJECT_NAME=my-app
+COMPILE_MODE=webpack
+BUILD_PATH=./webpack/webpack.dev.js
+DEBUG=true
\ No newline at end of file
diff --git a/.eslintignore b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.eslintignore
similarity index 100%
rename from .eslintignore
rename to packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.eslintignore
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.eslintrc.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.eslintrc.js
new file mode 100644
index 00000000..273023f9
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.eslintrc.js
@@ -0,0 +1,54 @@
+module.exports = {
+ extends: ['@nce/eslint-config-nce'],
+ parser: 'babel-eslint',
+ env: {
+ amd: true,
+ es6: true,
+ browser: true,
+ node: false,
+ },
+ globals: {
+ Prel: true,
+ __webpack_public_path__: true,
+ Axios: true,
+ },
+ settings: {
+ 'import/resolver': {
+ webpack: {
+ config: 'webpack/webpack.basic.js',
+ },
+ },
+ },
+ rules: {
+ indent: [
+ 'error',
+ 4,
+ {
+ SwitchCase: 1,
+ flatTernaryExpressions: true,
+ },
+ ],
+ 'no-unused-vars': 'off', // 允许变量声明后未使用
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+ 'no-underscore-dangle': ['off', 'always'], // 允许私有变量 _xxx的变量命名方式
+ 'react/jsx-indent-props': [2, 4], // 验证JSX中的props缩进
+ 'react/prop-types': 0, // 防止在React组件定义中丢失props验证
+ 'react/jsx-indent': [
+ // 解决react里面的缩进问题
+ 'error',
+ 4,
+ ],
+ 'filenames/match-exported': 0,
+ 'react/jsx-one-expression-per-line': 0, // 关闭一个表达式必须换行设定
+ 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], // 允许在 .js 和 .jsx 文件中使用 jsx
+ 'consistent-return': 0,
+ 'comma-dangle': [2, 'never'], // 组和对象键值对最后一个逗号, never参数:不能带末尾的逗号, always参数:必须带末尾的逗号
+ 'react/button-has-type': 0, // button无需强制声明类型
+ 'react/no-array-index-key': 0, // 允许使用数组index作为组件的key
+ 'global-require': 0, // 允许require语句不出现在顶层中
+ 'no-nested-ternary': 0, // 允许嵌套三元表达式
+ 'no-unused-expressions': 0, // 允许使用未执行的表达式。比如fn是一个函数,允许 fn && fn()
+ 'no-throw-literal': 0, // 允许throw抛出对象格式
+ '@typescript-eslint/member-ordering': 0, // 禁用TypeScript声明规范
+ },
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.gitignore b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.gitignore
new file mode 100644
index 00000000..30ca8b5e
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.gitignore
@@ -0,0 +1,5 @@
+/node_modules
+.idea
+.vscode
+package-lock.json
+/build
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.horizon.ts b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.horizon.ts
new file mode 100644
index 00000000..7f3bb9ea
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.horizon.ts
@@ -0,0 +1,4 @@
+export default {
+ enableMock: true,
+ mockPath: './mock',
+};
diff --git a/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.prettierignore b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.prettierignore
new file mode 100644
index 00000000..a3360cac
--- /dev/null
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.prettierignore
@@ -0,0 +1,4 @@
+node_modules/
+webpack/
+build/
+public/
diff --git a/.prettierrc.js b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.prettierrc.js
similarity index 53%
rename from .prettierrc.js
rename to packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.prettierrc.js
index da8f33e7..3b898b2a 100644
--- a/.prettierrc.js
+++ b/packages/create-inula/lib/generators/InulaJS-antd/templates/webpack/.prettierrc.js
@@ -1,20 +1,3 @@
-/*
- * Copyright (c) 2020 Huawei Technologies Co.,Ltd.
- *
- * InulaJS is licensed under Mulan PSL v2.
- * You can use this software according to the terms and conditions of the Mulan PSL v2.
- * You may obtain a copy of Mulan PSL v2 at:
- *
- * http://license.coscl.org.cn/MulanPSL2
- *
- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
- * See the Mulan PSL v2 for more details.
- */
-
-'use strict';
-
module.exports = {
printWidth: 120, // 一行120字符数,如果超过会进行换行
tabWidth: 2, // tab等2个空格
@@ -25,7 +8,7 @@ module.exports = {
jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格
- bracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
+ jsxBracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的
+