@ -0,0 +1,154 @@ | 
				
			|||||
 | 
					# ---> Go | 
				
			||||
 | 
					# Binaries for programs and plugins | 
				
			||||
 | 
					*.exe | 
				
			||||
 | 
					*.exe~ | 
				
			||||
 | 
					*.dll | 
				
			||||
 | 
					*.so | 
				
			||||
 | 
					*.dylib | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Test binary, built with `go test -c` | 
				
			||||
 | 
					*.test | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Output of the go coverage tool, specifically when used with LiteIDE | 
				
			||||
 | 
					*.out | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Dependency directories (remove the comment below to include it) | 
				
			||||
 | 
					# vendor/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# ---> Node | 
				
			||||
 | 
					# Logs | 
				
			||||
 | 
					logs | 
				
			||||
 | 
					*.log | 
				
			||||
 | 
					npm-debug.log* | 
				
			||||
 | 
					yarn-debug.log* | 
				
			||||
 | 
					yarn-error.log* | 
				
			||||
 | 
					lerna-debug.log* | 
				
			||||
 | 
					.pnpm-debug.log* | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Diagnostic reports (https://nodejs.org/api/report.html) | 
				
			||||
 | 
					report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Runtime data | 
				
			||||
 | 
					pids | 
				
			||||
 | 
					*.pid | 
				
			||||
 | 
					*.seed | 
				
			||||
 | 
					*.pid.lock | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Directory for instrumented libs generated by jscoverage/JSCover | 
				
			||||
 | 
					lib-cov | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Coverage directory used by tools like istanbul | 
				
			||||
 | 
					coverage | 
				
			||||
 | 
					*.lcov | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# nyc test coverage | 
				
			||||
 | 
					.nyc_output | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | 
				
			||||
 | 
					.grunt | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Bower dependency directory (https://bower.io/) | 
				
			||||
 | 
					bower_components | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# node-waf configuration | 
				
			||||
 | 
					.lock-wscript | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Compiled binary addons (https://nodejs.org/api/addons.html) | 
				
			||||
 | 
					build/Release | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Dependency directories | 
				
			||||
 | 
					node_modules | 
				
			||||
 | 
					jspm_packages/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Snowpack dependency directory (https://snowpack.dev/) | 
				
			||||
 | 
					web_modules/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# TypeScript cache | 
				
			||||
 | 
					*.tsbuildinfo | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Optional npm cache directory | 
				
			||||
 | 
					.npm | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Optional eslint cache | 
				
			||||
 | 
					.eslintcache | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Microbundle cache | 
				
			||||
 | 
					.rpt2_cache/ | 
				
			||||
 | 
					.rts2_cache_cjs/ | 
				
			||||
 | 
					.rts2_cache_es/ | 
				
			||||
 | 
					.rts2_cache_umd/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Optional REPL history | 
				
			||||
 | 
					.node_repl_history | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Output of 'npm pack' | 
				
			||||
 | 
					*.tgz | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Yarn Integrity file | 
				
			||||
 | 
					.yarn-integrity | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# dotenv environment variables file | 
				
			||||
 | 
					.env | 
				
			||||
 | 
					.env.test | 
				
			||||
 | 
					.env.production | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# parcel-bundler cache (https://parceljs.org/) | 
				
			||||
 | 
					.cache | 
				
			||||
 | 
					.parcel-cache | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Next.js build output | 
				
			||||
 | 
					.next | 
				
			||||
 | 
					out | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Nuxt.js build / generate output | 
				
			||||
 | 
					.nuxt | 
				
			||||
 | 
					dist | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Gatsby files | 
				
			||||
 | 
					.cache/ | 
				
			||||
 | 
					# Comment in the public line in if your project uses Gatsby and not Next.js | 
				
			||||
 | 
					# https://nextjs.org/blog/next-9-1#public-directory-support | 
				
			||||
 | 
					# public | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# vuepress build output | 
				
			||||
 | 
					.vuepress/dist | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Serverless directories | 
				
			||||
 | 
					.serverless/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# FuseBox cache | 
				
			||||
 | 
					.fusebox/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# DynamoDB Local files | 
				
			||||
 | 
					.dynamodb/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# TernJS port file | 
				
			||||
 | 
					.tern-port | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# Stores VSCode versions used for testing VSCode extensions | 
				
			||||
 | 
					.vscode-test | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# yarn v2 | 
				
			||||
 | 
					.yarn/cache | 
				
			||||
 | 
					.yarn/unplugged | 
				
			||||
 | 
					.yarn/build-state.yml | 
				
			||||
 | 
					.yarn/install-state.gz | 
				
			||||
 | 
					.pnp.* | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					*yarn.lock | 
				
			||||
 | 
					*package-lock.json | 
				
			||||
 | 
					*log/ | 
				
			||||
 | 
					*downloadFiles/ | 
				
			||||
 | 
					web/client/assets/color.less | 
				
			||||
 | 
					package-lock.json | 
				
			||||
 | 
					development.text | 
				
			||||
 | 
					development.log | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					web/node_modules | 
				
			||||
 | 
					web/log | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# weapp | 
				
			||||
 | 
					project.private.config.json | 
				
			||||
 | 
					miniprogram_npm | 
				
			||||
 | 
					web/log/development.txt | 
				
			||||
 | 
					api/log/development.log | 
				
			||||
@ -0,0 +1 @@ | 
				
			|||||
 | 
					# 飞尚码尚来二维码管理系统 | 
				
			||||
@ -0,0 +1,50 @@ | 
				
			|||||
 | 
					{ | 
				
			||||
 | 
					    // 使用 IntelliSense 了解相关属性。  | 
				
			||||
 | 
					    // 悬停以查看现有属性的描述。 | 
				
			||||
 | 
					    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 | 
				
			||||
 | 
					    "version": "0.2.0", | 
				
			||||
 | 
					    "configurations": [ | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            "type": "node", | 
				
			||||
 | 
					            "request": "launch", | 
				
			||||
 | 
					            "name": "启动 API", | 
				
			||||
 | 
					            "program": "${workspaceRoot}/server.js", | 
				
			||||
 | 
					            "env": { | 
				
			||||
 | 
					                "NODE_ENV": "development" | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            "args": [ | 
				
			||||
 | 
					                "-p 4900", | 
				
			||||
 | 
					                // 研发 | 
				
			||||
 | 
					                // "-g postgres://FashionAdmin:123456@10.8.30.39:5432/Inspection", | 
				
			||||
 | 
					                "-g postgres://postgres:123456@10.8.16.77:5432/qrcode", | 
				
			||||
 | 
					                // 测试 | 
				
			||||
 | 
					                // "--apiEmisUrl http://10.8.30.161:1111", | 
				
			||||
 | 
					                // "--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5", | 
				
			||||
 | 
					                // "--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa", | 
				
			||||
 | 
					                // "--qnbkt dev-hr", | 
				
			||||
 | 
					                // "--qndmn http://resources.anxinyun.cn", | 
				
			||||
 | 
					                // "--qndmn http://rjkwed13l.hn-bkt.clouddn.com", | 
				
			||||
 | 
					                "--qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu", | 
				
			||||
 | 
					                "--qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5", | 
				
			||||
 | 
					                "--qnbkt anxinyun-test", | 
				
			||||
 | 
					                "--qndmn http://test.resources.anxinyun.cn", | 
				
			||||
 | 
					            ] | 
				
			||||
 | 
					        }, | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            "type": "node", | 
				
			||||
 | 
					            "request": "launch", | 
				
			||||
 | 
					            "name": "run mocha", | 
				
			||||
 | 
					            "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", | 
				
			||||
 | 
					            "stopOnEntry": false, | 
				
			||||
 | 
					            "args": [ | 
				
			||||
 | 
					                "app/test/*.test.js", | 
				
			||||
 | 
					                "--no-timeouts" | 
				
			||||
 | 
					            ], | 
				
			||||
 | 
					            "cwd": "${workspaceRoot}", | 
				
			||||
 | 
					            "runtimeExecutable": null, | 
				
			||||
 | 
					            "env": { | 
				
			||||
 | 
					                "NODE_ENV": "development" | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    ] | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,36 @@ | 
				
			|||||
 | 
					FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12-dev as builder | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					COPY ./api/  /var/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					WORKDIR /var/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					EXPOSE 8080 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					RUN npm config set registry=https://nexus.ngaiot.com/repository/fs-npm/ | 
				
			||||
 | 
					RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json | 
				
			||||
 | 
					RUN npm cache clean -f | 
				
			||||
 | 
					RUN rm -rf package-lock.json | 
				
			||||
 | 
					RUN npm install --registry https://nexus.ngaiot.com/repository/fs-npm/ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					COPY --from=builder --chown=node /var/app  /home/node/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					WORKDIR /home/node/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					CMD ["node", "server.js"] | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# 旧版本构建方式 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# COPY . /var/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# WORKDIR /var/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# EXPOSE 8080 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# CMD ["-u", "http://localhost:8088"] | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# ENTRYPOINT [ "node", "server.js" ] | 
				
			||||
@ -0,0 +1,3 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = require('./lib'); | 
				
			||||
@ -0,0 +1,110 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					const Hex = require('crypto-js/enc-hex'); | 
				
			||||
 | 
					const SHA1 = require('crypto-js/sha1'); | 
				
			||||
 | 
					const MD5 = require('crypto-js/md5'); | 
				
			||||
 | 
					const moment = require('moment'); | 
				
			||||
 | 
					const uuid = require('uuid'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function login(ctx, next) { | 
				
			||||
 | 
					    const transaction = await ctx.fs.dc.orm.transaction(); | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const params = ctx.request.body; | 
				
			||||
 | 
					        let password = Hex.stringify(MD5(params.password)); | 
				
			||||
 | 
					        const userRes = await models.User.findOne({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                username: params.username, | 
				
			||||
 | 
					                password: password, | 
				
			||||
 | 
					                delete: false, | 
				
			||||
 | 
					                enable: true | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            attributes: { exclude: ['password'] }, | 
				
			||||
 | 
					            include: [{ | 
				
			||||
 | 
					                attributes: ["resourceId"], | 
				
			||||
 | 
					                model: models.UserResource | 
				
			||||
 | 
					            }] | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if (!userRes) { | 
				
			||||
 | 
					            ctx.status = 400; | 
				
			||||
 | 
					            ctx.body = { | 
				
			||||
 | 
					                "message": "账号或密码错误" | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if (userRes) | 
				
			||||
 | 
					            if (userRes && !userRes.enable) { | 
				
			||||
 | 
					                ctx.status = 400; | 
				
			||||
 | 
					                ctx.body = { message: "该用户已被禁用" } | 
				
			||||
 | 
					            } else { | 
				
			||||
 | 
					                const token = uuid.v4(); | 
				
			||||
 | 
					                let deptInfo = null; | 
				
			||||
 | 
					                if (userRes) { | 
				
			||||
 | 
					                    const { departmentId } = userRes.dataValues; | 
				
			||||
 | 
					                    deptInfo = await models.Department.findOne({ | 
				
			||||
 | 
					                        where: { | 
				
			||||
 | 
					                            id: departmentId | 
				
			||||
 | 
					                        } | 
				
			||||
 | 
					                    }) | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                if (!userRes) { | 
				
			||||
 | 
					                    ctx.status = 400; | 
				
			||||
 | 
					                    ctx.body = { message: "暂无登录权限,请联系管理员" } | 
				
			||||
 | 
					                    return; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                let userData = userRes.dataValues; | 
				
			||||
 | 
					                let userRslt = Object.assign(userData, { | 
				
			||||
 | 
					                    authorized: true, | 
				
			||||
 | 
					                    token: token, | 
				
			||||
 | 
					                    userResources: userRes ? userRes.userResources.map(r => r.resourceId) : [], | 
				
			||||
 | 
					                    type: deptInfo ? deptInfo.type : '', | 
				
			||||
 | 
					                    deptName: deptInfo ? deptInfo.name : '', | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					                await models.UserToken.create({ | 
				
			||||
 | 
					                    token: token, | 
				
			||||
 | 
					                    userInfo: userRslt, | 
				
			||||
 | 
					                    expired: moment().add(30, 'days').format() | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                ctx.status = 200; | 
				
			||||
 | 
					                ctx.body = userRslt; | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        await transaction.commit(); | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        await transaction.rollback(); | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "登录失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function logout(ctx) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const params = ctx.request.body; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        await models.UserToken.destroy({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                token: params.token, | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            message: typeof error == 'string' ? error : undefined | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = { | 
				
			||||
 | 
					    login, | 
				
			||||
 | 
					    logout, | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,87 @@ | 
				
			|||||
 | 
					async function getResource(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					         | 
				
			||||
 | 
					        const res = await models.Resource.findAll({ | 
				
			||||
 | 
					            where: { parentResource: null }, | 
				
			||||
 | 
					            include: [{ | 
				
			||||
 | 
					                model: models.Resource, | 
				
			||||
 | 
					            }] | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.body = res; | 
				
			||||
 | 
					        ctx.status = 200; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "查询所有权限数据失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					async function getUserResource(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { userId } = ctx.query; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        const res = await models.UserResource.findAll({ | 
				
			||||
 | 
					            where: { userId: userId }, | 
				
			||||
 | 
					            include: [{ | 
				
			||||
 | 
					                model: models.Resource, | 
				
			||||
 | 
					            }] | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.body = res; | 
				
			||||
 | 
					        ctx.status = 200; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "查询用户权限数据失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function updateUserRes(ctx, next) { | 
				
			||||
 | 
					    const transaction = await ctx.fs.dc.orm.transaction(); | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { userId, resCode } = ctx.request.body; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        const res = await models.UserResource.findAll({ | 
				
			||||
 | 
					            attributes: ["resourceId"], | 
				
			||||
 | 
					            raw: true, | 
				
			||||
 | 
					            where: { userId: userId } | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        const addRes = resCode.filter(r => !res.some(rr => rr.resourceId == r)).map(r => { return { userId: userId, resourceId: r } }); | 
				
			||||
 | 
					        const delRes = res.filter(r => !resCode.includes(r.resourceId)).map(r => r.resourceId); | 
				
			||||
 | 
					        addRes.length && await models.UserResource.bulkCreate(addRes, { transaction: transaction }); | 
				
			||||
 | 
					        delRes.length && await models.UserResource.destroy({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                resourceId: { $in: delRes }, | 
				
			||||
 | 
					                userId: userId | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            transaction: transaction | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					        await transaction.commit(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        await transaction.rollback(); | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "更新用户权限数据失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = { | 
				
			||||
 | 
					    getResource, | 
				
			||||
 | 
					    getUserResource, | 
				
			||||
 | 
					    updateUserRes | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,332 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					const Hex = require('crypto-js/enc-hex'); | 
				
			||||
 | 
					const MD5 = require('crypto-js/md5'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function getDepMessage(ctx, next) { | 
				
			||||
 | 
					    let error = { name: 'FindError', message: '获取部门列表失败' }; | 
				
			||||
 | 
					    let rslt = []; | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        let list = await models.Department.findAll({}); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        let deptMap = [] | 
				
			||||
 | 
					        list.filter(l => !l.dependence).map(ld => {//一级
 | 
				
			||||
 | 
					            deptMap.push({ | 
				
			||||
 | 
					                id: ld.id, | 
				
			||||
 | 
					                name: ld.name, | 
				
			||||
 | 
					                dependence: ld.dependence, | 
				
			||||
 | 
					                subordinate: [] | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        list.filter(l => l.dependence).map(ld => {//二级
 | 
				
			||||
 | 
					            let parent = deptMap.find(dm => dm.id == ld.dependence); | 
				
			||||
 | 
					            if (parent) { | 
				
			||||
 | 
					                parent.subordinate.push({ | 
				
			||||
 | 
					                    id: ld.id, | 
				
			||||
 | 
					                    name: ld.name, | 
				
			||||
 | 
					                    dependence: ld.dependence, | 
				
			||||
 | 
					                    subordinate: [] | 
				
			||||
 | 
					                }) | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					        rslt = deptMap; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        error = null; | 
				
			||||
 | 
					    } catch (err) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${err}`); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    if (error) { | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = error; | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					        ctx.status = 200; | 
				
			||||
 | 
					        ctx.body = rslt; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function createDept(ctx, next) { | 
				
			||||
 | 
					    const models = ctx.fs.dc.models; | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        let rslt = ctx.request.body; | 
				
			||||
 | 
					        await models.Department.create(Object.assign({}, rslt, { read: 1 })) | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					        ctx.body = { message: '新建部门成功' } | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { message: '新建部门失败' } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function updateDept(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { id } = ctx.params; | 
				
			||||
 | 
					        const body = ctx.request.body; | 
				
			||||
 | 
					        await models.Department.update( | 
				
			||||
 | 
					            body, | 
				
			||||
 | 
					            { where: { id: id } } | 
				
			||||
 | 
					        ) | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					        ctx.body = { message: '修改部门成功' } | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { message: '修改部门失败' } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function delDept(ctx, next) { | 
				
			||||
 | 
					    let errMsg = "删除部门失败"; | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { id } = ctx.params; | 
				
			||||
 | 
					        let list = await models.Department.findAll({}); | 
				
			||||
 | 
					        let deptIds = list.map(l => l.id); | 
				
			||||
 | 
					        const allUsers = await models.User.findAll({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                departmentId: { $in: deptIds }, | 
				
			||||
 | 
					                delete: false | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					        const childrenDept = await models.Department.findAll({ where: { dependence: id } }) | 
				
			||||
 | 
					        const childrenUser = allUsers.filter(au => au.departmentId == id); | 
				
			||||
 | 
					        if (childrenUser.length || childrenDept.length) { | 
				
			||||
 | 
					            errMsg = '请先删除部门下的用户或子部门'; | 
				
			||||
 | 
					            throw errMsg; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        await models.Department.destroy({ where: { id: id } }); | 
				
			||||
 | 
					        await models.Department.destroy({ where: { dependence: id } }); | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					        ctx.body = { message: '删除部门成功' } | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { message: error } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function getUser(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { depId } = ctx.params; | 
				
			||||
 | 
					        let userRes = null; | 
				
			||||
 | 
					        if (depId !== 'undefined' && depId !== 'null') { | 
				
			||||
 | 
					            userRes = await models.User.findAll({ | 
				
			||||
 | 
					                where: { | 
				
			||||
 | 
					                    departmentId: parseInt(depId), | 
				
			||||
 | 
					                    delete: false | 
				
			||||
 | 
					                }, | 
				
			||||
 | 
					                attributes: { exclude: ['password'] }, | 
				
			||||
 | 
					                order: [['id', 'asc']], | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					            userRes = await models.User.findAll({ | 
				
			||||
 | 
					                where: { | 
				
			||||
 | 
					                    delete: false | 
				
			||||
 | 
					                }, | 
				
			||||
 | 
					                attributes: { exclude: ['password'] }, | 
				
			||||
 | 
					                order: [['id', 'asc']], | 
				
			||||
 | 
					                include: [{ | 
				
			||||
 | 
					                    required: true, | 
				
			||||
 | 
					                    model: models.Department, | 
				
			||||
 | 
					                    attributes: ['id', 'name'], | 
				
			||||
 | 
					                }] | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.status = 200; | 
				
			||||
 | 
					        ctx.body = userRes | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "获取用户信息失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function creatUser(ctx, next) { | 
				
			||||
 | 
					    let errMsg = "新建用户失败" | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const data = ctx.request.body; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        let repeatUserNameCount = await models.User.count({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                username: data.phone, | 
				
			||||
 | 
					                delete: false | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if (repeatUserNameCount) { | 
				
			||||
 | 
					            errMsg = '已有当前用户名' | 
				
			||||
 | 
					            throw errMsg | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        await models.User.create({ | 
				
			||||
 | 
					            role: data.role, | 
				
			||||
 | 
					            name: data.name, | 
				
			||||
 | 
					            username: data.phone, | 
				
			||||
 | 
					            password: Hex.stringify(MD5(data.password)), | 
				
			||||
 | 
					            departmentId: data.departmentId, | 
				
			||||
 | 
					            email: data.email, | 
				
			||||
 | 
					            enable: data.enable, | 
				
			||||
 | 
					            delete: false, | 
				
			||||
 | 
					            phone: data.phone, | 
				
			||||
 | 
					            post: data.post, | 
				
			||||
 | 
					            structure: data.structure | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": errMsg | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function updateUser(ctx, next) { | 
				
			||||
 | 
					    let errMsg = "修改用户失败" | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const data = ctx.request.body; | 
				
			||||
 | 
					        const { id } = ctx.params; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        let repeatUserNameCount = await models.User.count({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                username: data.username | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if (repeatUserNameCount) { | 
				
			||||
 | 
					            errMsg = '已有当前用户名' | 
				
			||||
 | 
					            throw errMsg | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        await models.User.update({ | 
				
			||||
 | 
					            role: data.role, | 
				
			||||
 | 
					            name: data.name, | 
				
			||||
 | 
					            username: data.phone, | 
				
			||||
 | 
					            departmentId: data.departmentId, | 
				
			||||
 | 
					            email: data.email, | 
				
			||||
 | 
					            enable: data.enable, | 
				
			||||
 | 
					            delete: false, | 
				
			||||
 | 
					            phone: data.phone, | 
				
			||||
 | 
					            post: data.post, | 
				
			||||
 | 
					            structure: data.structure | 
				
			||||
 | 
					        }, { | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                id: id | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": errMsg | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function deleteUser(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { ids } = ctx.params; | 
				
			||||
 | 
					        const userIds = ids.split(','); | 
				
			||||
 | 
					        await models.User.update({ | 
				
			||||
 | 
					            delete: true, | 
				
			||||
 | 
					        }, { | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                id: { $in: userIds }, | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "删除用户失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					async function resetPwd(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { id } = ctx.params; | 
				
			||||
 | 
					        const data = ctx.request.body; | 
				
			||||
 | 
					        await models.User.update({ | 
				
			||||
 | 
					            password: Hex.stringify(MD5(data.password)), | 
				
			||||
 | 
					        }, { | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                id: id, | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					        ctx.status = 204; | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "重置用户密码失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** | 
				
			||||
 | 
					 * 修改用户密码 | 
				
			||||
 | 
					 * @params {userId-用户Id} ctx  | 
				
			||||
 | 
					 * @request.body {password-用户新密码} ctx  | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					async function updateUserPassword(ctx, next) { | 
				
			||||
 | 
					    try { | 
				
			||||
 | 
					        const models = ctx.fs.dc.models; | 
				
			||||
 | 
					        const { userId } = ctx.params; | 
				
			||||
 | 
					        const { password } = ctx.request.body; | 
				
			||||
 | 
					        if (!password) { | 
				
			||||
 | 
					            ctx.status = 400; | 
				
			||||
 | 
					            ctx.body = { "message": "请输入修改密码" }; | 
				
			||||
 | 
					            return; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        const userRes = await models.User.findOne({ | 
				
			||||
 | 
					            where: { | 
				
			||||
 | 
					                id: userId | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            attributes: ['id'] | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					        if (userRes) { | 
				
			||||
 | 
					            await models.User.update({ password: Hex.stringify(MD5(password)) }, { where: { id: userId, } }); | 
				
			||||
 | 
					            ctx.status = 204; | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					            ctx.status = 400; | 
				
			||||
 | 
					            ctx.body = { | 
				
			||||
 | 
					                "message": "用户不存在" | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } catch (error) { | 
				
			||||
 | 
					        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			||||
 | 
					        ctx.status = 400; | 
				
			||||
 | 
					        ctx.body = { | 
				
			||||
 | 
					            "message": "修改用户密码失败" | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = { | 
				
			||||
 | 
					    getDepMessage, | 
				
			||||
 | 
					    createDept, | 
				
			||||
 | 
					    updateDept, | 
				
			||||
 | 
					    delDept, | 
				
			||||
 | 
					    getUser, | 
				
			||||
 | 
					    creatUser, | 
				
			||||
 | 
					    updateUser, | 
				
			||||
 | 
					    deleteUser, | 
				
			||||
 | 
					    resetPwd, | 
				
			||||
 | 
					    updateUserPassword, | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,68 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const fs = require('fs'); | 
				
			||||
 | 
					const path = require('path'); | 
				
			||||
 | 
					const utils = require('./utils') | 
				
			||||
 | 
					const routes = require('./routes'); | 
				
			||||
 | 
					//const redisConnect = require('./service/redis')
 | 
				
			||||
 | 
					const socketConect = require('./service/socket') | 
				
			||||
 | 
					//const paasRequest = require('./service/paasRequest');
 | 
				
			||||
 | 
					const authenticator = require('./middlewares/authenticator'); | 
				
			||||
 | 
					//const clickHouseClient = require('./service/clickHouseClient')
 | 
				
			||||
 | 
					const schedule = require('./schedule') | 
				
			||||
 | 
					// const apiLog = require('./middlewares/api-log');
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports.entry = function (app, router, opts) { | 
				
			||||
 | 
					    app.fs.logger.log('info', '[FS-AUTH]', 'Inject auth and api mv into router.'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api = app.fs.api || {}; | 
				
			||||
 | 
					    app.fs.opts = opts || {}; | 
				
			||||
 | 
					    app.fs.utils = app.fs.utils || {}; | 
				
			||||
 | 
					    app.fs.api.authAttr = app.fs.api.authAttr || {}; | 
				
			||||
 | 
					    app.fs.api.logAttr = app.fs.api.logAttr || {}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 顺序固定 ↓ 
 | 
				
			||||
 | 
					    //redisConnect(app, opts)
 | 
				
			||||
 | 
					    socketConect(app, opts) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 实例其他平台请求方法
 | 
				
			||||
 | 
					    //paasRequest(app, opts)
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // clickHouse 数据库 client 
 | 
				
			||||
 | 
					    //clickHouseClient(app, opts)
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 工具类函数
 | 
				
			||||
 | 
					    utils(app, opts) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 定时任务
 | 
				
			||||
 | 
					    schedule(app, opts) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    //鉴权中间件
 | 
				
			||||
 | 
					    router.use(authenticator(app, opts)); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 日志记录
 | 
				
			||||
 | 
					    // router.use(apiLog(app, opts));
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    router = routes(app, router, opts); | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Sequelize, models: {} }
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 模型关系摘出来 初始化之后再定义关系才行
 | 
				
			||||
 | 
					    fs.readdirSync(path.join(__dirname, '/models')).forEach((filename) => { | 
				
			||||
 | 
					        require(`./models/${filename}`)(dc) | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const { Department, User, UserResource, Resource, } = dc.models; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    UserResource.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' }); | 
				
			||||
 | 
					    User.hasMany(UserResource, { foreignKey: 'userId', sourceKey: 'id' }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    UserResource.belongsTo(Resource, { foreignKey: 'resourceId', targetKey: 'code' }); | 
				
			||||
 | 
					    Resource.hasMany(UserResource, { foreignKey: 'resourceId', sourceKey: 'code' }); | 
				
			||||
 | 
					    Resource.hasMany(Resource, { foreignKey: 'parentResource', sourceKey: 'code' }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    User.belongsTo(Department, { foreignKey: 'departmentId', targetKey: 'id' }); | 
				
			||||
 | 
					    Department.hasMany(User, { foreignKey: 'departmentId', sourceKey: 'id' }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,83 @@ | 
				
			|||||
 | 
					/** | 
				
			||||
 | 
					 * Created by PengPeng on 2017/4/26. | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const moment = require('moment'); | 
				
			||||
 | 
					const pathToRegexp = require('path-to-regexp'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					function factory(app, opts) { | 
				
			||||
 | 
					    async function sendToEsAsync(producer, payloads) { | 
				
			||||
 | 
					        return new Promise((resolve, reject) => { | 
				
			||||
 | 
					            producer.send(payloads, function (err) { | 
				
			||||
 | 
					                if (err) { | 
				
			||||
 | 
					                    reject(err); | 
				
			||||
 | 
					                } else { | 
				
			||||
 | 
					                    resolve(); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					        }) | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    async function logger(ctx, next) { | 
				
			||||
 | 
					        const { path, method } = ctx; | 
				
			||||
 | 
					        const start = Date.now(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        // 等待路由处理
 | 
				
			||||
 | 
					        await next(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        try { | 
				
			||||
 | 
					            let logAttr = null; | 
				
			||||
 | 
					            for (let prop in app.fs.api.logAttr) { | 
				
			||||
 | 
					                let keys = []; | 
				
			||||
 | 
					                let re = pathToRegexp(prop.replace(/\:[A-Za-z_\-]+\b/g, '(\\d+)'), keys); | 
				
			||||
 | 
					                if (re.test(`${method}${path}`)) { | 
				
			||||
 | 
					                    logAttr = app.fs.api.logAttr[prop]; | 
				
			||||
 | 
					                    break; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            let parameter = null, parameterShow = null, user_id, _token, app_key; | 
				
			||||
 | 
					            if (ctx.fs.api) { | 
				
			||||
 | 
					                const { actionParameter, actionParameterShow, userId, token, appKey } = ctx.fs.api; | 
				
			||||
 | 
					                parameter = actionParameter; | 
				
			||||
 | 
					                parameterShow = actionParameterShow; | 
				
			||||
 | 
					                user_id = userId; | 
				
			||||
 | 
					                _token = token; | 
				
			||||
 | 
					                app_key = appKey; | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					            const producer = ctx.fs.kafka.producer; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            const message = { | 
				
			||||
 | 
					                log_time: moment().toISOString(), | 
				
			||||
 | 
					                method: method, | 
				
			||||
 | 
					                content: logAttr ? logAttr.content : '', | 
				
			||||
 | 
					                parameter: JSON.stringify(parameter) || JSON.stringify(ctx.request.body), | 
				
			||||
 | 
					                parameter_show: parameterShow, | 
				
			||||
 | 
					                visible: logAttr ? logAttr.visible : true, | 
				
			||||
 | 
					                cost: Date.now() - start, | 
				
			||||
 | 
					                status_code: ctx.status, | 
				
			||||
 | 
					                url: ctx.request.url, | 
				
			||||
 | 
					                user_agent: ctx.request.headers["user-agent"], | 
				
			||||
 | 
					                user_id: user_id, | 
				
			||||
 | 
					                session: _token, | 
				
			||||
 | 
					                app_key: app_key, | 
				
			||||
 | 
					                header: JSON.stringify(ctx.request.headers), | 
				
			||||
 | 
					                ip: ctx.request.headers["x-real-ip"] || ctx.ip | 
				
			||||
 | 
					            }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            const payloads = [{ | 
				
			||||
 | 
					                topic: `${opts.kafka.topicPrefix}`, | 
				
			||||
 | 
					                messages: [JSON.stringify(message)], | 
				
			||||
 | 
					                partition: 0 | 
				
			||||
 | 
					            }]; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            // await sendToEsAsync(producer, payloads);
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        } catch (e) { | 
				
			||||
 | 
					            ctx.fs.logger.error(`日志记录失败: ${e}`); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return logger; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = factory; | 
				
			||||
@ -0,0 +1,23 @@ | 
				
			|||||
 | 
					/** | 
				
			||||
 | 
					 * Created by PengLing on 2018/1/2. | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const Attachment = require('fs-attachment'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = { | 
				
			||||
 | 
					    entry: function (app, router, opts) { | 
				
			||||
 | 
					        const attachment = new Attachment(opts); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        app.fs = app.fs || {}; | 
				
			||||
 | 
					        app.fs.attachment = attachment; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        app.fs.logger.log('debug', 'init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        return async (ctx, next) => { | 
				
			||||
 | 
					            ctx.fs = ctx.fs || {}; | 
				
			||||
 | 
					            ctx.fs.attachment = attachment; | 
				
			||||
 | 
					            await next(); | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,149 @@ | 
				
			|||||
 | 
					/** | 
				
			||||
 | 
					 * Created by PengLing on 2017/3/27. | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const pathToRegexp = require('path-to-regexp'); | 
				
			||||
 | 
					const util = require('util'); | 
				
			||||
 | 
					const moment = require('moment'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class ExcludesUrls { | 
				
			||||
 | 
					    constructor(opts) { | 
				
			||||
 | 
					        this.allUrls = undefined; | 
				
			||||
 | 
					        this.reload(opts); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    sanitizePath (path) { | 
				
			||||
 | 
					        if (!path) return '/'; | 
				
			||||
 | 
					        const p = '/' + path.replace(/^\/+/i, '').replace(/\/+$/, '').replace(/\/{2,}/, '/'); | 
				
			||||
 | 
					        return p; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    reload (opts) { | 
				
			||||
 | 
					        // load all url
 | 
				
			||||
 | 
					        if (!this.allUrls) { | 
				
			||||
 | 
					            this.allUrls = opts; | 
				
			||||
 | 
					            let that = this; | 
				
			||||
 | 
					            this.allUrls.forEach(function (url, i, arr) { | 
				
			||||
 | 
					                if (typeof url === "string") { | 
				
			||||
 | 
					                    url = { p: url, o: '*' }; | 
				
			||||
 | 
					                    arr[i] = url; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                const keys = []; | 
				
			||||
 | 
					                let eachPath = url.p; | 
				
			||||
 | 
					                url.p = (!eachPath || eachPath === '(.*)' || util.isRegExp(eachPath)) ? eachPath : that.sanitizePath(eachPath); | 
				
			||||
 | 
					                url.pregexp = pathToRegexp(eachPath, keys); | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    isExcluded (path, method) { | 
				
			||||
 | 
					        return this.allUrls.some(function (url) { | 
				
			||||
 | 
					            return !url.auth | 
				
			||||
 | 
					                && url.pregexp.test(path) | 
				
			||||
 | 
					                && (url.o === '*' || url.o.indexOf(method) !== -1); | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** | 
				
			||||
 | 
					 * 判断Url是否不鉴权 | 
				
			||||
 | 
					 * @param {*} opts {exclude: [*] or []},'*'或['*']:跳过所有路由; []:所有路由都要验证 | 
				
			||||
 | 
					 * @param {*} path 当前request的path | 
				
			||||
 | 
					 * @param {*} method 当前request的method | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					let isPathExcluded = function (opts, path, method) { | 
				
			||||
 | 
					    let excludeAll = Boolean(opts.exclude && opts.exclude.length && opts.exclude[0] == '*'); | 
				
			||||
 | 
					    let excludes = null; | 
				
			||||
 | 
					    if (!excludeAll) { | 
				
			||||
 | 
					        let excludeOpts = opts.exclude || []; | 
				
			||||
 | 
					        excludeOpts.push({ p: '/login', o: 'POST' }); | 
				
			||||
 | 
					        excludeOpts.push({ p: '/logout', o: 'PUT' }); | 
				
			||||
 | 
					        excludes = new ExcludesUrls(excludeOpts); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    let excluded = excludeAll || excludes.isExcluded(path, method); | 
				
			||||
 | 
					    return excluded; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					let authorizeToken = async function (ctx, token) { | 
				
			||||
 | 
					    let rslt = null; | 
				
			||||
 | 
					    const tokenFormatRegexp = /^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$/g; | 
				
			||||
 | 
					    if (token && tokenFormatRegexp.test(token)) { | 
				
			||||
 | 
					        try { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            const authorizeRes = await ctx.fs.dc.models.UserToken.findOne({ | 
				
			||||
 | 
					                where: { | 
				
			||||
 | 
					                    token: token | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            }) | 
				
			||||
 | 
					            const { userInfo, expired } = authorizeRes; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            if (expired && moment().valueOf() <= moment(expired).valueOf()) { | 
				
			||||
 | 
					                rslt = { | 
				
			||||
 | 
					                    'authorized': userInfo.authorized, | 
				
			||||
 | 
					                    'resources': (userInfo || {}).resources || [], | 
				
			||||
 | 
					                }; | 
				
			||||
 | 
					                ctx.fs.api.userId = userInfo.id; | 
				
			||||
 | 
					                ctx.fs.api.userInfo = userInfo; | 
				
			||||
 | 
					                ctx.fs.api.token = token; | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } catch (err) { | 
				
			||||
 | 
					            const { error } = err.response || {}; | 
				
			||||
 | 
					            ctx.fs.logger.log('[anxinyun]', '[AUTH] failed', (error || {}).message || `cannot GET /users/${token}`); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return rslt; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					let isResourceAvailable = function (resources, options) { | 
				
			||||
 | 
					    let authCode = null; | 
				
			||||
 | 
					    // authorize user by authorization attribute
 | 
				
			||||
 | 
					    const { authAttr, method, path } = options; | 
				
			||||
 | 
					    for (let prop in authAttr) { | 
				
			||||
 | 
					        let keys = []; | 
				
			||||
 | 
					        let re = pathToRegexp(prop.replace(/\:[A-Za-z_\-]+\b/g, '(\\d+)'), keys); | 
				
			||||
 | 
					        if (re.test(`${method}${path}`)) { | 
				
			||||
 | 
					            authCode = authAttr[prop]; | 
				
			||||
 | 
					            break; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return !authCode || (resources || []).some(code => code === authCode); | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					function factory (app, opts) { | 
				
			||||
 | 
					    return async function auth (ctx, next) { | 
				
			||||
 | 
					        const { path, method, header, query } = ctx; | 
				
			||||
 | 
					        ctx.fs.logger.log('[AUTH] start', path, method); | 
				
			||||
 | 
					        ctx.fs.api = ctx.fs.api || {}; | 
				
			||||
 | 
					        ctx.fs.port = opts.port; | 
				
			||||
 | 
					        ctx.redis = app.redis; | 
				
			||||
 | 
					        ctx.redisTools = app.redisTools; | 
				
			||||
 | 
					        let error = null; | 
				
			||||
 | 
					        if (path) { | 
				
			||||
 | 
					            if (!isPathExcluded(opts, path, method)) { | 
				
			||||
 | 
					                const user = await authorizeToken(ctx, header.token || query.token); | 
				
			||||
 | 
					                if (user && user.authorized) { | 
				
			||||
 | 
					                    // if (!isResourceAvailable(user.resources, { authAttr: app.fs.auth.authAttr, path, method })) {
 | 
				
			||||
 | 
					                    //     error = { status: 403, name: 'Forbidden' }
 | 
				
			||||
 | 
					                    // } else {
 | 
				
			||||
 | 
					                    //     error = { status: 401, name: 'Unauthorized' }
 | 
				
			||||
 | 
					                    // }
 | 
				
			||||
 | 
					                } else { | 
				
			||||
 | 
					                    error = { status: 401, name: 'Unauthorized' } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					            error = { status: 401, name: 'Unauthorized' }; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        if (error) { | 
				
			||||
 | 
					            ctx.fs.logger.log('[AUTH] failed', path, method); | 
				
			||||
 | 
					            ctx.status = error.status; | 
				
			||||
 | 
					            ctx.body = error.name; | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					            ctx.fs.logger.log('[AUTH] passed', path, method); | 
				
			||||
 | 
					            await next(); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = factory; | 
				
			||||
@ -0,0 +1,45 @@ | 
				
			|||||
 | 
					/* eslint-disable*/ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = dc => { | 
				
			||||
 | 
					  const DataTypes = dc.ORM; | 
				
			||||
 | 
					  const sequelize = dc.orm; | 
				
			||||
 | 
					  const Department = sequelize.define("department", { | 
				
			||||
 | 
					    id: { | 
				
			||||
 | 
					      type: DataTypes.INTEGER, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: true, | 
				
			||||
 | 
					      field: "id", | 
				
			||||
 | 
					      autoIncrement: true, | 
				
			||||
 | 
					      unique: "department_id_uindex" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    name: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "name", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    dependence: { | 
				
			||||
 | 
					      type: DataTypes.INTEGER, | 
				
			||||
 | 
					      allowNull: true, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: "上级部门/从属", | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "dependence", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					  }, { | 
				
			||||
 | 
					    tableName: "department", | 
				
			||||
 | 
					    comment: "", | 
				
			||||
 | 
					    indexes: [] | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  dc.models.Department = Department; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  return Department; | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,44 @@ | 
				
			|||||
 | 
					/* eslint-disable*/ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = dc => { | 
				
			||||
 | 
					  const DataTypes = dc.ORM; | 
				
			||||
 | 
					  const sequelize = dc.orm; | 
				
			||||
 | 
					  const Resource = sequelize.define("resource", { | 
				
			||||
 | 
					    code: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: true, | 
				
			||||
 | 
					      field: "code", | 
				
			||||
 | 
					      autoIncrement: false, | 
				
			||||
 | 
					      unique: "resource_code_uindex" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    name: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "name", | 
				
			||||
 | 
					      autoIncrement: false, | 
				
			||||
 | 
					      unique: "resource_name_uindex" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    parentResource: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: true, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "parent_resource", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  }, { | 
				
			||||
 | 
					    tableName: "resource", | 
				
			||||
 | 
					    comment: "", | 
				
			||||
 | 
					    indexes: [] | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					  dc.models.Resource = Resource; | 
				
			||||
 | 
					  return Resource; | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,105 @@ | 
				
			|||||
 | 
					/* eslint-disable*/ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = dc => { | 
				
			||||
 | 
					  const DataTypes = dc.ORM; | 
				
			||||
 | 
					  const sequelize = dc.orm; | 
				
			||||
 | 
					  const User = sequelize.define("user", { | 
				
			||||
 | 
					    id: { | 
				
			||||
 | 
					      type: DataTypes.INTEGER, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: true, | 
				
			||||
 | 
					      field: "id", | 
				
			||||
 | 
					      autoIncrement: true | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    name: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "name", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    username: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: "用户名 账号", | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "username", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    password: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "password", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    departmentId: { | 
				
			||||
 | 
					      type: DataTypes.INTEGER, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: "部门id", | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "department_id", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    email: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: true, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "email", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    enable: { | 
				
			||||
 | 
					      type: DataTypes.BOOLEAN, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: "启用状态", | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "enable", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    delete: { | 
				
			||||
 | 
					      type: DataTypes.BOOLEAN, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "delete", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    phone: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: "手机号(小程序使用手机号登录)", | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "phone", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    post: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: true, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: "职位", | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "post", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					  }, { | 
				
			||||
 | 
					    tableName: "user", | 
				
			||||
 | 
					    comment: "", | 
				
			||||
 | 
					    indexes: [] | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					  dc.models.User = User; | 
				
			||||
 | 
					  return User; | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,52 @@ | 
				
			|||||
 | 
					/* eslint-disable*/ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = dc => { | 
				
			||||
 | 
					  const DataTypes = dc.ORM; | 
				
			||||
 | 
					  const sequelize = dc.orm; | 
				
			||||
 | 
					  const UserResource = sequelize.define("userResource", { | 
				
			||||
 | 
					    id: { | 
				
			||||
 | 
					      type: DataTypes.INTEGER, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: true, | 
				
			||||
 | 
					      field: "id", | 
				
			||||
 | 
					      autoIncrement: true, | 
				
			||||
 | 
					      unique: "post_resource_id_uindex" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    userId: { | 
				
			||||
 | 
					      type: DataTypes.INTEGER, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "user_id", | 
				
			||||
 | 
					      autoIncrement: false, | 
				
			||||
 | 
					      references: { | 
				
			||||
 | 
					        key: "id", | 
				
			||||
 | 
					        model: "post" | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    resourceId: { | 
				
			||||
 | 
					      type: DataTypes.STRING, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "resource", | 
				
			||||
 | 
					      autoIncrement: false, | 
				
			||||
 | 
					      references: { | 
				
			||||
 | 
					        key: "code", | 
				
			||||
 | 
					        model: "resource" | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  }, { | 
				
			||||
 | 
					    tableName: "user_resource", | 
				
			||||
 | 
					    comment: "", | 
				
			||||
 | 
					    indexes: [] | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  dc.models.UserResource = UserResource; | 
				
			||||
 | 
					  return UserResource; | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,43 @@ | 
				
			|||||
 | 
					/* eslint-disable*/ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = dc => { | 
				
			||||
 | 
					  const DataTypes = dc.ORM; | 
				
			||||
 | 
					  const sequelize = dc.orm; | 
				
			||||
 | 
					  const UserToken = sequelize.define("userToken", { | 
				
			||||
 | 
					    token: { | 
				
			||||
 | 
					      type: DataTypes.UUIDV4, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: true, | 
				
			||||
 | 
					      field: "token", | 
				
			||||
 | 
					      autoIncrement: false, | 
				
			||||
 | 
					      unique: "user_token_token_uindex" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    userInfo: { | 
				
			||||
 | 
					      type: DataTypes.JSONB, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "user_info", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    expired: { | 
				
			||||
 | 
					      type: DataTypes.DATE, | 
				
			||||
 | 
					      allowNull: false, | 
				
			||||
 | 
					      defaultValue: null, | 
				
			||||
 | 
					      comment: null, | 
				
			||||
 | 
					      primaryKey: false, | 
				
			||||
 | 
					      field: "expired", | 
				
			||||
 | 
					      autoIncrement: false | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  }, { | 
				
			||||
 | 
					    tableName: "user_token", | 
				
			||||
 | 
					    comment: "", | 
				
			||||
 | 
					    indexes: [] | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					  dc.models.UserToken = UserToken; | 
				
			||||
 | 
					  return UserToken; | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,11 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const auth = require('../../controllers/auth'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, router, opts) { | 
				
			||||
 | 
					    app.fs.api.logAttr['POST/login'] = { content: '登录', visible: true }; | 
				
			||||
 | 
					    router.post('/login', auth.login); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['PUT/logout'] = { content: '登出', visible: false }; | 
				
			||||
 | 
					    router.put('/logout', auth.logout); | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,17 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const path = require('path'); | 
				
			||||
 | 
					const fs = require('fs'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, router, opts) { | 
				
			||||
 | 
					   fs.readdirSync(__dirname).forEach((filename) => { | 
				
			||||
 | 
					      if (filename.indexOf('.') !== 0 && fs.lstatSync(path.join(__dirname, filename)).isDirectory()) { | 
				
			||||
 | 
					         fs.readdirSync(path.join(__dirname, filename)).forEach((api) => { | 
				
			||||
 | 
					            if (api.indexOf('.') == 0 || api.indexOf('.js') == -1) return; | 
				
			||||
 | 
					            require(`./${filename}/${api}`)(app, router, opts); | 
				
			||||
 | 
					         }); | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   return router; | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,28 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const Authority = require('../../controllers/organization/authority'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, router, opts) { | 
				
			||||
 | 
					    /** | 
				
			||||
 | 
					    * @api {GET} resource 查询所有权限码. | 
				
			||||
 | 
					    * @apiVersion 1.0.0 | 
				
			||||
 | 
					    * @apiGroup Org | 
				
			||||
 | 
					    */ | 
				
			||||
 | 
					    app.fs.api.logAttr['GET/resource'] = { content: '查询所有权限码', visible: true }; | 
				
			||||
 | 
					    router.get('resource', Authority.getResource); | 
				
			||||
 | 
					    /** | 
				
			||||
 | 
					     * @api {GET} user/resource 查询用户权限. | 
				
			||||
 | 
					     * @apiVersion 1.0.0 | 
				
			||||
 | 
					     * @apiGroup Org | 
				
			||||
 | 
					     */ | 
				
			||||
 | 
					    app.fs.api.logAttr['GET/user/resource'] = { content: '查询用户权限', visible: true }; | 
				
			||||
 | 
					    router.get('user/resource', Authority.getUserResource); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    /** | 
				
			||||
 | 
					     * @api {POST} user/resource 更新用户权限. | 
				
			||||
 | 
					     * @apiVersion 1.0.0 | 
				
			||||
 | 
					     * @apiGroup Org | 
				
			||||
 | 
					     */ | 
				
			||||
 | 
					    app.fs.api.logAttr['POST/user/resource'] = { content: '更新用户权限', visible: true }; | 
				
			||||
 | 
					    router.post('user/resource', Authority.updateUserRes); | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,42 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const user = require('../../controllers/organization/user'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, router, opts) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['GET/organization/department'] = { content: '获取部门信息', visible: false }; | 
				
			||||
 | 
					    router.get('/organization/department', user.getDepMessage); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['POST/organization/dept/add'] = { content: '新增部门', visible: true }; | 
				
			||||
 | 
					    router.post('/organization/dept/add', user.createDept); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['PUT/organization/dept/:id/modify'] = { content: '修改部门', visible: true }; | 
				
			||||
 | 
					    router.put('/organization/dept/:id/modify', user.updateDept); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['DELETE/organization/dept/:id'] = { content: '删除部门', visible: true }; | 
				
			||||
 | 
					    router.del('/organization/dept/:id', user.delDept); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['GET/organization/department/:depId/user'] = { content: '获取部门下用户信息', visible: false }; | 
				
			||||
 | 
					    router.get('/organization/department/:depId/user', user.getUser); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['POST/organization/department/user'] = { content: '创建部门下用户信息', visible: false }; | 
				
			||||
 | 
					    router.post('/organization/department/user', user.creatUser); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['PUT/organization/department/user/:id'] = { content: '修改部门下用户信息', visible: false }; | 
				
			||||
 | 
					    router.put('/organization/department/user/:id', user.updateUser); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['DEL/organization/department/user/:ids'] = { content: '删除部门下用户信息', visible: false }; | 
				
			||||
 | 
					    router.del('/organization/department/user/:ids', user.deleteUser); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    app.fs.api.logAttr['PUT/organization/department/user/resetPwd/:id'] = { content: '重置用户密码', visible: false }; | 
				
			||||
 | 
					    router.put('/organization/department/user/resetPwd/:id', user.resetPwd); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    /** | 
				
			||||
 | 
					     * @api {PUT} user/password/:id 修改用户密码 | 
				
			||||
 | 
					     * @apiVersion 1.0.0 | 
				
			||||
 | 
					     * @apiGroup Organization | 
				
			||||
 | 
					     */ | 
				
			||||
 | 
					    app.fs.api.logAttr['PUT/user/password/:userId'] = { content: '修改用户密码', visible: false }; | 
				
			||||
 | 
					    router.put('/user/password/:userId', user.updateUserPassword); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,49 @@ | 
				
			|||||
 | 
					const moment = require('moment') | 
				
			||||
 | 
					const rimraf = require('rimraf'); | 
				
			||||
 | 
					const fs = require("fs"); | 
				
			||||
 | 
					const path = require("path") | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					let TEST = false | 
				
			||||
 | 
					// TEST = true
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, opts) { | 
				
			||||
 | 
					    const clearExpiredData = app.fs.scheduleInit( | 
				
			||||
 | 
					        { | 
				
			||||
 | 
					            interval: '42 24 4 */3 * *', | 
				
			||||
 | 
					            immediate: TEST, | 
				
			||||
 | 
					            proRun: !TEST, | 
				
			||||
 | 
					        }, | 
				
			||||
 | 
					        async () => { | 
				
			||||
 | 
					            try { | 
				
			||||
 | 
					                const { models } = app.fs.dc | 
				
			||||
 | 
					                const now = moment().format('YYYY-MM-DD HH:mm:ss') | 
				
			||||
 | 
					                await models.UserToken.destroy({ | 
				
			||||
 | 
					                    where: { | 
				
			||||
 | 
					                        expired: { $lt: now } | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                }) | 
				
			||||
 | 
					                 | 
				
			||||
 | 
					                fs.readdir(path.join(__dirname, `../../downloadFiles`), function (err, files) { | 
				
			||||
 | 
					                    if (err) { | 
				
			||||
 | 
					                        return; | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                    files.forEach((file) => { | 
				
			||||
 | 
					                        fs.stat(path.join(__dirname, `../../downloadFiles/${file}`), (err, stats) => { | 
				
			||||
 | 
					                            if (err) { | 
				
			||||
 | 
					                                //return;
 | 
				
			||||
 | 
					                            } else { | 
				
			||||
 | 
					                                rimraf.sync(path.join(__dirname, `../../downloadFiles/${file}`)); | 
				
			||||
 | 
					                            } | 
				
			||||
 | 
					                        }); | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					            } catch (error) { | 
				
			||||
 | 
					                app.fs.logger.error(`sechedule: clearExpiredToken, error: ${error}`); | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    ); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    return { | 
				
			||||
 | 
					        clearExpiredData | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,36 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const fs = require('fs'); | 
				
			||||
 | 
					const nodeSchedule = require('node-schedule'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// 将定时任务汇集未来可根据需要选取操作
 | 
				
			||||
 | 
					module.exports = async function (app, opts) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   const scheduleInit = ({ | 
				
			||||
 | 
					      interval, immediate, proRun, | 
				
			||||
 | 
					   }, callback) => { | 
				
			||||
 | 
					      if (proRun && opts.dev) { | 
				
			||||
 | 
					         return; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					      const j = nodeSchedule.scheduleJob(interval, callback); | 
				
			||||
 | 
					      if (immediate && (!proRun || (proRun && !opts.dev))) { | 
				
			||||
 | 
					         setTimeout(callback, 0) | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					      return j; | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   app.fs.scheduleInit = scheduleInit | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   fs.readdirSync(__dirname).forEach((filename) => { | 
				
			||||
 | 
					      if (!['index.js'].some(f => filename == f)) { | 
				
			||||
 | 
					         const scheduleList = require(`./${filename}`)(app, opts) | 
				
			||||
 | 
					         for (let k of Object.keys(scheduleList)) { | 
				
			||||
 | 
					            console.info(`定时任务 ${k} 启动`); | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					         app.fs.schedule = { | 
				
			||||
 | 
					            ...app.fs.schedule, | 
				
			||||
 | 
					            ...scheduleList, | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   }); | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,36 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					const { ClickHouse } = require('clickhouse'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					function factory (app, opts) { | 
				
			||||
 | 
					   if (opts.clickHouse) { | 
				
			||||
 | 
					      try { | 
				
			||||
 | 
					         app.fs.clickHouse = {} | 
				
			||||
 | 
					         const { url, port, user, password, db = [] } = opts.clickHouse | 
				
			||||
 | 
					         for (let d of db) { | 
				
			||||
 | 
					            if (d.name && d.db) { | 
				
			||||
 | 
					               app.fs.clickHouse[d.name] = new ClickHouse({ | 
				
			||||
 | 
					                  url: url, | 
				
			||||
 | 
					                  port: port, | 
				
			||||
 | 
					                  debug: opts.dev, | 
				
			||||
 | 
					                  format: "json", | 
				
			||||
 | 
					                  basicAuth: user && password ? { | 
				
			||||
 | 
					                     username: user, | 
				
			||||
 | 
					                     password: password, | 
				
			||||
 | 
					                  } : null, | 
				
			||||
 | 
					                  config: { | 
				
			||||
 | 
					                     database: d.db, | 
				
			||||
 | 
					                  }, | 
				
			||||
 | 
					               }) | 
				
			||||
 | 
					               console.info(`ClickHouse ${d.name} 初始化完成`); | 
				
			||||
 | 
					            } else { | 
				
			||||
 | 
					               throw 'opts.clickHouse 参数错误!' | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } catch (error) { | 
				
			||||
 | 
					         console.error(error) | 
				
			||||
 | 
					         process.exit(-1); | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = factory; | 
				
			||||
@ -0,0 +1,67 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					const request = require('superagent') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class paasRequest { | 
				
			||||
 | 
					   constructor(root, { query = {} } = {}, option) { | 
				
			||||
 | 
					      this.root = root; | 
				
			||||
 | 
					      this.query = query | 
				
			||||
 | 
					      this.option = option | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   #buildUrl = (url) => { | 
				
			||||
 | 
					      return `${this.root}/${url}`; | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   #resultHandler = (resolve, reject) => { | 
				
			||||
 | 
					      return (err, res) => { | 
				
			||||
 | 
					         if (err) { | 
				
			||||
 | 
					            reject(err); | 
				
			||||
 | 
					         } else { | 
				
			||||
 | 
					            resolve(res[this.option.dataWord]); | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      }; | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   get = (url, { query = {}, header = {} } = {}) => { | 
				
			||||
 | 
					      return new Promise((resolve, reject) => { | 
				
			||||
 | 
					         request.get(this.#buildUrl(url)).set(header).query(Object.assign(query, this.query)).end(this.#resultHandler(resolve, reject)); | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   post = (url, { data = {}, query = {}, header = {} } = {}) => { | 
				
			||||
 | 
					      return new Promise((resolve, reject) => { | 
				
			||||
 | 
					         request.post(this.#buildUrl(url)).set(header).query(Object.assign(query, this.query)).send(data).end(this.#resultHandler(resolve, reject)); | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   put = (url, { data = {}, header = {}, query = {}, } = {}) => { | 
				
			||||
 | 
					      return new Promise((resolve, reject) => { | 
				
			||||
 | 
					         request.put(this.#buildUrl(url)).set(header).query(Object.assign(query, this.query)).send(data).end(this.#resultHandler(resolve, reject)); | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   delete = (url, { header = {}, query = {} } = {}) => { | 
				
			||||
 | 
					      return new Promise((resolve, reject) => { | 
				
			||||
 | 
					         request.delete(this.#buildUrl(url)).set(header).query(Object.assign(query, this.query)).end(this.#resultHandler(resolve, reject)); | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					function factory (app, opts) { | 
				
			||||
 | 
					   if (opts.pssaRequest) { | 
				
			||||
 | 
					      try { | 
				
			||||
 | 
					         for (let r of opts.pssaRequest) { | 
				
			||||
 | 
					            if (r.name && r.root) { | 
				
			||||
 | 
					               app.fs[r.name] = new paasRequest(r.root, { ...(r.params || {}) }, { dataWord: r.dataWord || 'body' }) | 
				
			||||
 | 
					            } else { | 
				
			||||
 | 
					               throw 'opts.pssaRequest 参数错误!' | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } catch (error) { | 
				
			||||
 | 
					         console.error(error) | 
				
			||||
 | 
					         process.exit(-1); | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = factory; | 
				
			||||
@ -0,0 +1,41 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					// https://github.com/luin/ioredis
 | 
				
			||||
 | 
					const redis = require("ioredis") | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = async function factory (app, opts) { | 
				
			||||
 | 
					   let client = opts.redis.pwd ? | 
				
			||||
 | 
					      new redis.Cluster([ | 
				
			||||
 | 
					         { | 
				
			||||
 | 
					            host: opts.redis.host, | 
				
			||||
 | 
					            port: opts.redis.port | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      ], { | 
				
			||||
 | 
					         redisOptions: { | 
				
			||||
 | 
					            password: opts.redis.pwd, | 
				
			||||
 | 
					         }, | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					      : new redis(opts.redis.port, opts.redis.host, { | 
				
			||||
 | 
					         password: opts.redis.pwd, | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   client.on("error", function (err) { | 
				
			||||
 | 
					      app.fs.logger.error('info', '[FS-AUTH-REDIS]', `redis connect error. ${opts.redis.host + ':' + opts.redis.port}`); | 
				
			||||
 | 
					      // console.error("Error :", err);
 | 
				
			||||
 | 
					      // process.exit(-1);
 | 
				
			||||
 | 
					   }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   client.on('connect', function () { | 
				
			||||
 | 
					      console.info(`redis connect success ${opts.redis.host + ':' + opts.redis.port}`); | 
				
			||||
 | 
					   }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   // 自定义方法
 | 
				
			||||
 | 
					   async function hdelall (key) { | 
				
			||||
 | 
					      const obj = await client.hgetall(key); | 
				
			||||
 | 
					      await client.hdel(key, Object.keys(obj)) | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   app.redis = client | 
				
			||||
 | 
					   app.redisTools = { | 
				
			||||
 | 
					      hdelall, | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,31 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					const moment = require('moment') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = async function factory (app, opts) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   app.socket.on('connection', async (socket) => { | 
				
			||||
 | 
					      console.info('WEB_SOCKET token:' + socket.handshake.query.token + ' 已连接:id ' + socket.id + ' 时间:' + moment(socket.handshake.time).format()); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      socket.on('disconnecting', async (reason) => { | 
				
			||||
 | 
					         const connectSeconds = moment().diff(moment(socket.handshake.time), 'seconds') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					         console.info('WEB_SOCKET token:' + socket.handshake.query.token + ' 已断开连接:' + reason + ' 连接时长:' + connectSeconds + 's'); | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					   }) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   // 使用测试 保持链接
 | 
				
			||||
 | 
					   // setInterval(async () => {
 | 
				
			||||
 | 
					   //    const { connected } = app.socket.sockets
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   //    const roomId = 'ROOM_' + Math.random()
 | 
				
			||||
 | 
					   //    // if (connected) {
 | 
				
			||||
 | 
					   //    //    for (let c in connected) {
 | 
				
			||||
 | 
					   //    //       connected[c].join(roomId)
 | 
				
			||||
 | 
					   //    //    }
 | 
				
			||||
 | 
					   //    //    app.socket.to(roomId).emit('TEST', { someProperty: `【星域 ROOM:${roomId}】呼叫自然选择号!!!`, })
 | 
				
			||||
 | 
					   //    // }
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   //    app.socket.emit('TEST', { someProperty: '【广播】呼叫青铜时代号!!!', })
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   // }, 3000)
 | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,17 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const path = require('path'); | 
				
			||||
 | 
					const fs = require('fs'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = async function (app, opts) { | 
				
			||||
 | 
					   fs.readdirSync(__dirname).forEach((filename) => { | 
				
			||||
 | 
					      if (!['index.js'].some(f => filename == f)) { | 
				
			||||
 | 
					         const utils = require(`./${filename}`)(app, opts) | 
				
			||||
 | 
					         console.log(`载入 ${filename} 工具集成功`); | 
				
			||||
 | 
					         app.fs.utils = { | 
				
			||||
 | 
					            ...app.fs.utils, | 
				
			||||
 | 
					            ...utils, | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   }); | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,62 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const moment = require('moment') | 
				
			||||
 | 
					const Core = require('@alicloud/pop-core'); | 
				
			||||
 | 
					const nodemailer = require('nodemailer') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, opts) { | 
				
			||||
 | 
					   const pushBySms = async ({ phone = [], templateCode, templateParam } = {}) => { | 
				
			||||
 | 
					      try { | 
				
			||||
 | 
					         if (phone.length) { | 
				
			||||
 | 
					            const client = new Core({ | 
				
			||||
 | 
					               accessKeyId: opts.sms.accessKey, | 
				
			||||
 | 
					               accessKeySecret: opts.sms.accessSecret, | 
				
			||||
 | 
					               endpoint: 'http://dysmsapi.aliyuncs.com',//固定
 | 
				
			||||
 | 
					               apiVersion: '2017-05-25'//固定
 | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					            const SendSmsRes = await client.request('SendSms', { | 
				
			||||
 | 
					               "PhoneNumbers": phone.join(','),//接收短信的手机号码。
 | 
				
			||||
 | 
					               "SignName": "隧道智慧运维助手",//短信签名名称。必须是已添加、并通过审核的短信签名。
 | 
				
			||||
 | 
					               "TemplateCode": templateCode,//短信模板ID。必须是已添加、并通过审核的短信签名;且发送国际/港澳台消息时,请使用国际/港澳台短信模版。
 | 
				
			||||
 | 
					               "TemplateParam": JSON.stringify(templateParam)//短信模板变量对应的实际值,JSON格式。
 | 
				
			||||
 | 
					            }, { | 
				
			||||
 | 
					               method: 'POST' | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					            return SendSmsRes | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } catch (error) { | 
				
			||||
 | 
					         throw error | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   const pushByEmail = async ({ email = [], title, text = '', html = '', attachments = undefined } = {}) => { | 
				
			||||
 | 
					      try { | 
				
			||||
 | 
					         let transporter = nodemailer.createTransport({ | 
				
			||||
 | 
					            host: opts.email.host, | 
				
			||||
 | 
					            port: opts.email.port, | 
				
			||||
 | 
					            secure: true, | 
				
			||||
 | 
					            auth: { | 
				
			||||
 | 
					               user: opts.email.sender.address, | 
				
			||||
 | 
					               pass: opts.email.sender.password, | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					         }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					         // send mail with defined transport object
 | 
				
			||||
 | 
					         await transporter.sendMail({ | 
				
			||||
 | 
					            from: `${opts.email.sender.name}<${opts.email.sender.address}>`, // sender address
 | 
				
			||||
 | 
					            to: email.join(','), // list of receivers 逗号分隔字符串
 | 
				
			||||
 | 
					            subject: title, // Subject line
 | 
				
			||||
 | 
					            text: text, // plain text body
 | 
				
			||||
 | 
					            html: html, // html body
 | 
				
			||||
 | 
					            attachments: attachments | 
				
			||||
 | 
					         }); | 
				
			||||
 | 
					      } catch (error) { | 
				
			||||
 | 
					         throw error | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   return { | 
				
			||||
 | 
					      pushByEmail, | 
				
			||||
 | 
					      pushBySms, | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,82 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					const fs = require('fs'); | 
				
			||||
 | 
					const xlsx = require('better-xlsx'); | 
				
			||||
 | 
					const path = require('path') | 
				
			||||
 | 
					const moment = require('moment') | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = function (app, opts) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   //递归创建目录 同步方法  
 | 
				
			||||
 | 
					   async function makeDir (dir) { | 
				
			||||
 | 
					      if (!fs.existsSync(dir)) { | 
				
			||||
 | 
					         makeDir(path.dirname(dir)) | 
				
			||||
 | 
					         fs.mkdirSync(dir, function (err) { | 
				
			||||
 | 
					            if (err) { | 
				
			||||
 | 
					               throw err | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					         }); | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   async function simpleExcelDown ({ data = [], header = [], fileName = moment().format('YYYY-MM-DD HH:mm:ss') } = {}) { | 
				
			||||
 | 
					      const fileDirPath = path.join(__dirname, `../../downloadFiles`) | 
				
			||||
 | 
					      makeDir(fileDirPath) | 
				
			||||
 | 
					      const file = new xlsx.File(); | 
				
			||||
 | 
					      const sheet_1 = file.addSheet('sheet_1'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      // header
 | 
				
			||||
 | 
					      const headerStyle = new xlsx.Style(); | 
				
			||||
 | 
					      headerStyle.align.h = 'center'; | 
				
			||||
 | 
					      headerStyle.align.v = 'center'; | 
				
			||||
 | 
					      headerStyle.border.right = 'thin'; | 
				
			||||
 | 
					      headerStyle.border.rightColor = '#000000'; | 
				
			||||
 | 
					      headerStyle.border.bottom = 'thin'; | 
				
			||||
 | 
					      headerStyle.border.bottomColor = '#000000'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const headerRow = sheet_1.addRow(); | 
				
			||||
 | 
					      const indexCell = headerRow.addCell(); | 
				
			||||
 | 
					      indexCell.value = '序号' | 
				
			||||
 | 
					      indexCell.style = headerStyle | 
				
			||||
 | 
					      for (let h of header) { | 
				
			||||
 | 
					         const cell = headerRow.addCell(); | 
				
			||||
 | 
					         cell.value = h.title; | 
				
			||||
 | 
					         cell.style = headerStyle | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      // data
 | 
				
			||||
 | 
					      const style = new xlsx.Style(); | 
				
			||||
 | 
					      style.align.h = 'left'; | 
				
			||||
 | 
					      style.align.v = 'center'; | 
				
			||||
 | 
					      style.border.right = 'thin'; | 
				
			||||
 | 
					      style.border.rightColor = '#000000'; | 
				
			||||
 | 
					      style.border.bottom = 'thin'; | 
				
			||||
 | 
					      style.border.bottomColor = '#000000'; | 
				
			||||
 | 
					      for (let i = 0; i < data.length; i++) { | 
				
			||||
 | 
					         const row = sheet_1.addRow(); | 
				
			||||
 | 
					         const indexCell = row.addCell(); | 
				
			||||
 | 
					         indexCell.value = i + 1 | 
				
			||||
 | 
					         indexCell.style = headerStyle | 
				
			||||
 | 
					         for (let h of header) { | 
				
			||||
 | 
					            const cell = row.addCell(); | 
				
			||||
 | 
					            cell.value = data[i][h.key] || h.defaultValue || '-'; | 
				
			||||
 | 
					            cell.style = style | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      const savePath = path.join(fileDirPath, fileName) | 
				
			||||
 | 
					      await new Promise(function (resolve, reject) { | 
				
			||||
 | 
					         file.saveAs() | 
				
			||||
 | 
					            .pipe(fs.createWriteStream(savePath)) | 
				
			||||
 | 
					            .on('finish', () => { | 
				
			||||
 | 
					               resolve() | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					      return savePath | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   return { | 
				
			||||
 | 
					      simpleExcelDown, | 
				
			||||
 | 
					      makeDir | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,150 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					/*jslint node:true*/ | 
				
			||||
 | 
					const path = require('path'); | 
				
			||||
 | 
					const os = require('os'); | 
				
			||||
 | 
					const moment = require('moment'); | 
				
			||||
 | 
					const args = require('args'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const dev = process.env.NODE_ENV == 'development'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// 启动参数
 | 
				
			||||
 | 
					args.option(['p', 'port'], '启动端口'); | 
				
			||||
 | 
					args.option(['g', 'pg'], 'postgre 服务 URL'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// 七牛云存储参数
 | 
				
			||||
 | 
					args.option('qnak', 'qiniuAccessKey'); | 
				
			||||
 | 
					args.option('qnsk', 'qiniuSecretKey'); | 
				
			||||
 | 
					args.option('qnbkt', 'qiniuBucket'); | 
				
			||||
 | 
					args.option('qndmn', 'qiniuDomain'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const flags = args.parse(process.argv); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const QRCODE_DB = process.env.QRCODE_DB || flags.pg; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// 七牛云存储参数
 | 
				
			||||
 | 
					const QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || flags.qndmn; | 
				
			||||
 | 
					const QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt; | 
				
			||||
 | 
					const QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak; | 
				
			||||
 | 
					const QINIU_SK = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					if (!QRCODE_DB || !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK) { | 
				
			||||
 | 
					   console.log('缺少启动参数,异常退出'); | 
				
			||||
 | 
					   args.showHelp(); | 
				
			||||
 | 
					   process.exit(-1); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const product = { | 
				
			||||
 | 
					   port: flags.port || 8080, | 
				
			||||
 | 
					   staticDirs: ['static'], | 
				
			||||
 | 
					   mws: [ | 
				
			||||
 | 
					      { | 
				
			||||
 | 
					         entry: require('@fs/attachment').entry, | 
				
			||||
 | 
					         opts: { | 
				
			||||
 | 
					            qiniu: { | 
				
			||||
 | 
					               domain: QINIU_DOMAIN_QNDMN_RESOURCE, | 
				
			||||
 | 
					               bucket: QINIU_BUCKET_RESOURCE, | 
				
			||||
 | 
					               accessKey: QINIU_AK, | 
				
			||||
 | 
					               secretKey: QINIU_SK | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            maxSize: 104857600, // 100M
 | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      }, { | 
				
			||||
 | 
					         entry: require('./app/lib/middlewares/attachment').entry, | 
				
			||||
 | 
					         opts: { | 
				
			||||
 | 
					            qiniu: { | 
				
			||||
 | 
					               accessKey: QINIU_AK, | 
				
			||||
 | 
					               secretKey: QINIU_SK, | 
				
			||||
 | 
					               bucket: QINIU_BUCKET_RESOURCE, | 
				
			||||
 | 
					               domain: QINIU_DOMAIN_QNDMN_RESOURCE | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            maxSize: 104857600, // 100M
 | 
				
			||||
 | 
					            //  uploadPath: 'other'
 | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      }, { | 
				
			||||
 | 
					         entry: require('./app').entry, | 
				
			||||
 | 
					         opts: { | 
				
			||||
 | 
					            dev, | 
				
			||||
 | 
					            exclude: [ | 
				
			||||
 | 
					               //    "*"
 | 
				
			||||
 | 
					            ], // 不做认证的路由,也可以使用 exclude: ["*"]  跳过所有路由
 | 
				
			||||
 | 
					            qiniu: { | 
				
			||||
 | 
					               domain: QINIU_DOMAIN_QNDMN_RESOURCE, | 
				
			||||
 | 
					               bucket: QINIU_BUCKET_RESOURCE, | 
				
			||||
 | 
					               accessKey: QINIU_AK, | 
				
			||||
 | 
					               secretKey: QINIU_SK | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            // sms: {
 | 
				
			||||
 | 
					            //    ///阿里云-安心云
 | 
				
			||||
 | 
					            //    accessKey: 'LTAI5tAFdjz7j38aNF2C9Qe8',
 | 
				
			||||
 | 
					            //    accessSecret: '1trYkmiqfBtvZL6BxkNH2uQcQQPs0S'
 | 
				
			||||
 | 
					            // },
 | 
				
			||||
 | 
					            // email: {
 | 
				
			||||
 | 
					            //    enabled: true,
 | 
				
			||||
 | 
					            //    host: 'smtp.exmail.qq.com',
 | 
				
			||||
 | 
					            //    port: 465,
 | 
				
			||||
 | 
					            //    sender: {
 | 
				
			||||
 | 
					            //       name: '运维服务',
 | 
				
			||||
 | 
					            //       address: 'fsiot@free-sun.com.cn',
 | 
				
			||||
 | 
					            //       password: 'Fs2689'
 | 
				
			||||
 | 
					            //    }
 | 
				
			||||
 | 
					            // },
 | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   ], | 
				
			||||
 | 
					   dc: { | 
				
			||||
 | 
					      url: QRCODE_DB, | 
				
			||||
 | 
					      opts: { | 
				
			||||
 | 
					         pool: { | 
				
			||||
 | 
					            max: 80, | 
				
			||||
 | 
					            min: 10, | 
				
			||||
 | 
					            idle: 10000 | 
				
			||||
 | 
					         }, | 
				
			||||
 | 
					         define: { | 
				
			||||
 | 
					            freezeTableName: true, // 固定表名
 | 
				
			||||
 | 
					            timestamps: false // 不含列 "createAt"/"updateAt"/"DeleteAt"
 | 
				
			||||
 | 
					         }, | 
				
			||||
 | 
					         timezone: '+08:00', | 
				
			||||
 | 
					         logging: false | 
				
			||||
 | 
					      }, | 
				
			||||
 | 
					      models: [require('./app').models] | 
				
			||||
 | 
					   }, | 
				
			||||
 | 
					   logger: { | 
				
			||||
 | 
					      level: 'info', | 
				
			||||
 | 
					      json: false, | 
				
			||||
 | 
					      filename: path.join(__dirname, 'log', 'runtime.log'), | 
				
			||||
 | 
					      colorize: false, | 
				
			||||
 | 
					      maxsize: 1024 * 1024 * 5, | 
				
			||||
 | 
					      rotationFormat: false, | 
				
			||||
 | 
					      zippedArchive: true, | 
				
			||||
 | 
					      maxFiles: 10, | 
				
			||||
 | 
					      prettyPrint: true, | 
				
			||||
 | 
					      label: '', | 
				
			||||
 | 
					      timestamp: () => moment().format('YYYY-MM-DD HH:mm:ss.SSS'), | 
				
			||||
 | 
					      eol: os.EOL, | 
				
			||||
 | 
					      tailable: true, | 
				
			||||
 | 
					      depth: null, | 
				
			||||
 | 
					      showLevel: true, | 
				
			||||
 | 
					      maxRetries: 1 | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const development = { | 
				
			||||
 | 
					   port: product.port, | 
				
			||||
 | 
					   staticDirs: product.staticDirs, | 
				
			||||
 | 
					   mws: product.mws, | 
				
			||||
 | 
					   dc: product.dc, | 
				
			||||
 | 
					   logger: product.logger | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					if (dev) { | 
				
			||||
 | 
					   // mws
 | 
				
			||||
 | 
					   for (let mw of development.mws) { | 
				
			||||
 | 
					      // if (mw.opts.exclude) mw.opts.exclude = ['*']; // 使用 ['*'] 跳过所有路由
 | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					   // logger
 | 
				
			||||
 | 
					   development.logger.filename = path.join(__dirname, 'log', 'development.log'); | 
				
			||||
 | 
					   development.logger.level = 'debug'; | 
				
			||||
 | 
					   development.dc.opts.logging = console.log; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = dev ? development : product; | 
				
			||||
@ -0,0 +1,49 @@ | 
				
			|||||
 | 
					{ | 
				
			||||
 | 
					    "name": "smart-emergency", | 
				
			||||
 | 
					    "version": "1.0.0", | 
				
			||||
 | 
					    "description": "fs smart emergency api", | 
				
			||||
 | 
					    "main": "server.js", | 
				
			||||
 | 
					    "scripts": { | 
				
			||||
 | 
					        "test": "set DEBUG=true&&\"node_modules/.bin/mocha\" --harmony --reporter spec app/test/*.test.js", | 
				
			||||
 | 
					        "start": "set NODE_ENV=development&&node server -p 4900 -g postgres://postgres:123456@10.8.16.77:5432/qrcode", | 
				
			||||
 | 
					        "start:linux": "export NODE_ENV=development&&node server -p 4900 -g postgres://postgres:123456@10.8.16.77:5432/qrcode", | 
				
			||||
 | 
					        "automate": "sequelize-automate -c sequelize-automate.config.js" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    "author": "", | 
				
			||||
 | 
					    "license": "MIT", | 
				
			||||
 | 
					    "repository": {}, | 
				
			||||
 | 
					    "dependencies": { | 
				
			||||
 | 
					        "@alicloud/pop-core": "^1.7.12", | 
				
			||||
 | 
					        "@fs/attachment": "^1.0.0", | 
				
			||||
 | 
					        "ali-oss": "^6.17.1", | 
				
			||||
 | 
					        "args": "^3.0.7", | 
				
			||||
 | 
					        "better-xlsx": "^0.7.6", | 
				
			||||
 | 
					        "clickhouse": "^2.6.0", | 
				
			||||
 | 
					        "crypto-js": "^4.0.0", | 
				
			||||
 | 
					        "file-saver": "^2.0.2", | 
				
			||||
 | 
					        "fs-attachment": "^1.0.0", | 
				
			||||
 | 
					        "fs-web-server-scaffold": "^2.0.2", | 
				
			||||
 | 
					        "ioredis": "^5.0.4", | 
				
			||||
 | 
					        "kafka-node": "^2.2.3", | 
				
			||||
 | 
					        "koa-convert": "^1.2.0", | 
				
			||||
 | 
					        "koa-proxy": "^0.9.0", | 
				
			||||
 | 
					        "moment": "^2.24.0", | 
				
			||||
 | 
					        "mqtt": "^4.3.7", | 
				
			||||
 | 
					        "node-schedule": "^2.1.0", | 
				
			||||
 | 
					        "nodemailer": "^6.7.7", | 
				
			||||
 | 
					        "path": "^0.12.7", | 
				
			||||
 | 
					        "path-to-regexp": "^3.0.0", | 
				
			||||
 | 
					        "pg": "^7.9.0", | 
				
			||||
 | 
					        "qrcode": "^1.5.1", | 
				
			||||
 | 
					        "qs": "^6.11.0", | 
				
			||||
 | 
					        "redis": "^3.1.2", | 
				
			||||
 | 
					        "request": "^2.88.2", | 
				
			||||
 | 
					        "rimraf": "^2.6.3", | 
				
			||||
 | 
					        "shortid": "^2.2.16", | 
				
			||||
 | 
					        "superagent": "^3.5.2", | 
				
			||||
 | 
					        "uuid": "^3.3.2" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    "devDependencies": { | 
				
			||||
 | 
					        "mocha": "^6.0.2" | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,35 @@ | 
				
			|||||
 | 
					module.exports = { | 
				
			||||
 | 
					    // 数据库配置 与 sequelize 相同
 | 
				
			||||
 | 
					    dbOptions: { | 
				
			||||
 | 
					        database: 'Inspection_20231016', | 
				
			||||
 | 
					        username: 'FashionAdmin', | 
				
			||||
 | 
					        password: '123456', | 
				
			||||
 | 
					        dialect: 'postgres', | 
				
			||||
 | 
					        host: '10.8.30.39', | 
				
			||||
 | 
					        port: 5432, | 
				
			||||
 | 
					        define: { | 
				
			||||
 | 
					            underscored: false, | 
				
			||||
 | 
					            freezeTableName: false, | 
				
			||||
 | 
					            charset: 'utf8mb4', | 
				
			||||
 | 
					            timezone: '+00: 00', | 
				
			||||
 | 
					            dialectOptions: { | 
				
			||||
 | 
					                collate: 'utf8_general_ci', | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            timestamps: false, | 
				
			||||
 | 
					        }, | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    options: { | 
				
			||||
 | 
					        type: 'freesun', // 指定 models 代码风格
 | 
				
			||||
 | 
					        camelCase: true, // Models 文件中代码是否使用驼峰命名
 | 
				
			||||
 | 
					        modalNameSuffix: false, // 模型名称是否带 ‘Model’ 后缀
 | 
				
			||||
 | 
					        fileNameCamelCase: false, // Model 文件名是否使用驼峰法命名,默认文件名会使用表名,如 `user_post.js`;如果为 true,则文件名为 `userPost.js`
 | 
				
			||||
 | 
					        dir: './app/lib/models', // 指定输出 models 文件的目录
 | 
				
			||||
 | 
					        typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义
 | 
				
			||||
 | 
					        emptyDir: false, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir`
 | 
				
			||||
 | 
					        tables: ['user', 'project'], // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性
 | 
				
			||||
 | 
					        skipTables: [], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性
 | 
				
			||||
 | 
					        tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中
 | 
				
			||||
 | 
					        ignorePrefix: ['t_',], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面
 | 
				
			||||
 | 
					        attrLength: false, // 在生成模型的字段中 是否生成 如 var(128)这种格式,公司一般使用 String ,则配置为 false
 | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,12 @@ | 
				
			|||||
 | 
					/** | 
				
			||||
 | 
					 * Created by rain on 2016/1/25. | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					/*jslint node:true*/ | 
				
			||||
 | 
					//from koa
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const scaffold = require('fs-web-server-scaffold'); | 
				
			||||
 | 
					const config = require('./config'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					module.exports = scaffold(config); | 
				
			||||
@ -0,0 +1,25 @@ | 
				
			|||||
 | 
					podTemplate { | 
				
			||||
 | 
					    node('pod-templ-jenkins-slave-common') { | 
				
			||||
 | 
							 | 
				
			||||
 | 
							env.IMAGE_NAME = "${IOT_IMAGES_REGISTRY}/${IOT}/${JOB_NAME}" | 
				
			||||
 | 
							env.IMAGE_NAME_SHORT = "${IOT}/${JOB_NAME}" | 
				
			||||
 | 
					        env.CODE_ADDR = "${GIT_ADDRESS}/free-sun/Inspection.git" | 
				
			||||
 | 
							 | 
				
			||||
 | 
						    stage('Run shell') {  | 
				
			||||
 | 
							    git branch: 'master', credentialsId: 'gitea-builder', url: "${CODE_ADDR}" | 
				
			||||
 | 
							     | 
				
			||||
 | 
							    container('image-builder') {			     | 
				
			||||
 | 
									sh''' | 
				
			||||
 | 
										pwd | 
				
			||||
 | 
										ls -al | 
				
			||||
 | 
										 | 
				
			||||
 | 
									    /kaniko/executor --context=${BUILD_WORKSPACE} --dockerfile=./api/Dockerfile --destination=${IMAGE_NAME}:${IMAGE_VERSION} --cache=false --cleanup  | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								    '''			     | 
				
			||||
 | 
							    } | 
				
			||||
 | 
								 | 
				
			||||
 | 
							    buildName "${IMAGE_NAME_SHORT}:${IMAGE_VERSION}" | 
				
			||||
 | 
							    buildDescription "${IMAGE_NAME}:${IMAGE_VERSION}"			 | 
				
			||||
 | 
							} | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,25 @@ | 
				
			|||||
 | 
					podTemplate { | 
				
			||||
 | 
					    node('pod-templ-jenkins-slave-common') { | 
				
			||||
 | 
							 | 
				
			||||
 | 
							env.IMAGE_NAME = "${IOT_IMAGES_REGISTRY}/${IOT}/${JOB_NAME}" | 
				
			||||
 | 
							env.IMAGE_NAME_SHORT = "${IOT}/${JOB_NAME}" | 
				
			||||
 | 
					        env.CODE_ADDR = "${GIT_ADDRESS}/free-sun/Inspection.git" | 
				
			||||
 | 
							 | 
				
			||||
 | 
						    stage('Run shell') {  | 
				
			||||
 | 
							    git branch: 'master', credentialsId: 'gitea-builder', url: "${CODE_ADDR}" | 
				
			||||
 | 
							     | 
				
			||||
 | 
							    container('image-builder') {			     | 
				
			||||
 | 
									sh''' | 
				
			||||
 | 
										pwd | 
				
			||||
 | 
										ls -al | 
				
			||||
 | 
										 | 
				
			||||
 | 
									    /kaniko/executor --context=${BUILD_WORKSPACE} --dockerfile=./web/Dockerfile --destination=${IMAGE_NAME}:${IMAGE_VERSION} --cache=false --cleanup  | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								    '''			     | 
				
			||||
 | 
							    } | 
				
			||||
 | 
								 | 
				
			||||
 | 
							    buildName "${IMAGE_NAME_SHORT}:${IMAGE_VERSION}" | 
				
			||||
 | 
							    buildDescription "${IMAGE_NAME}:${IMAGE_VERSION}"			 | 
				
			||||
 | 
							} | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,3 @@ | 
				
			|||||
 | 
					INSERT INTO "public"."department" VALUES (default, '默认部门', NULL); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					INSERT INTO "public"."user" VALUES (default, '管理员', 'SuperAdmin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL, 't', 'f', '123456789', NULL); | 
				
			||||
@ -0,0 +1,73 @@ | 
				
			|||||
 | 
					DROP SEQUENCE if EXISTS "public"."user_id_seq"; | 
				
			||||
 | 
					CREATE SEQUENCE "public"."user_id_seq" | 
				
			||||
 | 
					INCREMENT 1 | 
				
			||||
 | 
					MINVALUE  1 | 
				
			||||
 | 
					MAXVALUE 9223372036854775807 | 
				
			||||
 | 
					START 1 | 
				
			||||
 | 
					CACHE 1; | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."user"; | 
				
			||||
 | 
					CREATE TABLE "public"."user" ( | 
				
			||||
 | 
					  "id" int4 NOT NULL PRIMARY KEY DEFAULT nextval('user_id_seq'::regclass), | 
				
			||||
 | 
					  "name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "username" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "password" varchar(512) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "department_id" int4 NOT NULL, | 
				
			||||
 | 
					  "email" varchar(128) COLLATE "pg_catalog"."default", | 
				
			||||
 | 
					  "enable" bool NOT NULL DEFAULT true, | 
				
			||||
 | 
					  "delete" bool NOT NULL DEFAULT false, | 
				
			||||
 | 
					  "phone" varchar(20) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "post" varchar(64) COLLATE "pg_catalog"."default" | 
				
			||||
 | 
					); | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."user"."username" IS '用户名 账号'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."user"."department_id" IS '部门id'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."user"."enable" IS '启用状态'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."user"."phone" IS '手机号'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."user"."post" IS '职位'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."resource"; | 
				
			||||
 | 
					CREATE TABLE "public"."resource" ( | 
				
			||||
 | 
					  "code" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "parent_resource" varchar(128) COLLATE "pg_catalog"."default" | 
				
			||||
 | 
					); | 
				
			||||
 | 
					COMMENT ON TABLE "public"."resource" IS '权限字典'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DROP SEQUENCE if EXISTS "public"."user_resource_id_seq"; | 
				
			||||
 | 
					CREATE SEQUENCE "public"."user_resource_id_seq" | 
				
			||||
 | 
					INCREMENT 1 | 
				
			||||
 | 
					MINVALUE  1 | 
				
			||||
 | 
					MAXVALUE 9223372036854775807 | 
				
			||||
 | 
					START 1 | 
				
			||||
 | 
					CACHE 1; | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."user_resource"; | 
				
			||||
 | 
					CREATE TABLE "public"."user_resource" ( | 
				
			||||
 | 
					  "id" int4 NOT NULL DEFAULT nextval('user_resource_id_seq'::regclass), | 
				
			||||
 | 
					  "user_id" int4 NOT NULL, | 
				
			||||
 | 
					  "resource" varchar(128) COLLATE "pg_catalog"."default" NOT NULL | 
				
			||||
 | 
					); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."user_token"; | 
				
			||||
 | 
					CREATE TABLE "public"."user_token" ( | 
				
			||||
 | 
					  "token" uuid NOT NULL, | 
				
			||||
 | 
					  "user_info" jsonb NOT NULL, | 
				
			||||
 | 
					  "expired" timestamptz(6) NOT NULL | 
				
			||||
 | 
					); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DROP SEQUENCE if EXISTS "public"."department_id_seq"; | 
				
			||||
 | 
					CREATE SEQUENCE "public"."department_id_seq"  | 
				
			||||
 | 
					INCREMENT 1 | 
				
			||||
 | 
					MINVALUE  1 | 
				
			||||
 | 
					MAXVALUE 9223372036854775807 | 
				
			||||
 | 
					START 1 | 
				
			||||
 | 
					CACHE 1; | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."department"; | 
				
			||||
 | 
					CREATE TABLE "public"."department" ( | 
				
			||||
 | 
					  "id" int4 NOT NULL DEFAULT nextval('department_id_seq'::regclass), | 
				
			||||
 | 
					  "name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, | 
				
			||||
 | 
					  "dependence" int4 | 
				
			||||
 | 
					); | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."department"."dependence" IS '上级部门/从属'; | 
				
			||||
@ -0,0 +1,43 @@ | 
				
			|||||
 | 
					DROP TABLE IF EXISTS "public"."qrcode"; | 
				
			||||
 | 
					CREATE TABLE "public"."qrcode" ( | 
				
			||||
 | 
					  "id" serial, | 
				
			||||
 | 
					  "url" varchar(255) NOT NULL, | 
				
			||||
 | 
					  "name" varchar(128) NOT NULL, | 
				
			||||
 | 
					  "type" varchar(32) NOT NULL, | 
				
			||||
 | 
					  PRIMARY KEY ("id") | 
				
			||||
 | 
					); | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode"."name" IS '二维码名称'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode"."type" IS '类型(文件|链接)'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode"."url" IS '二维码图片存储链接'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."publicity_info"; | 
				
			||||
 | 
					CREATE TABLE "public"."publicity_info" ( | 
				
			||||
 | 
					  "id" serial, | 
				
			||||
 | 
					  "name" varchar(128) NOT NULL, | 
				
			||||
 | 
					  "type" varchar(32) NOT NULL, | 
				
			||||
 | 
					  "time" timestamptz NOT NULL, | 
				
			||||
 | 
					  "qrcode_id" int4 NOT NULL, | 
				
			||||
 | 
					  PRIMARY KEY ("id"), | 
				
			||||
 | 
					  CONSTRAINT "publicity_info_qrcode_id_fk" FOREIGN KEY ("qrcode_id") REFERENCES "public"."qrcode" ("id") | 
				
			||||
 | 
					); | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."publicity_info"."name" IS '宣传标题'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."publicity_info"."type" IS '类型'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."publicity_info"."time" IS '创建/更新时间'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."publicity_info"."qrcode_id" IS '关联二维码ID'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DROP TABLE IF EXISTS "public"."qrcode_files"; | 
				
			||||
 | 
					CREATE TABLE "public"."qrcode_files" ( | 
				
			||||
 | 
					  "id" serial, | 
				
			||||
 | 
					  "qrcode_id" int4 NOT NULL, | 
				
			||||
 | 
					  "file_name" varchar(128) NOT NULL, | 
				
			||||
 | 
					  "file_size" int4 NOT NULL, | 
				
			||||
 | 
					  "file_url" varchar(255) NOT NULL, | 
				
			||||
 | 
					  PRIMARY KEY ("id"), | 
				
			||||
 | 
					  CONSTRAINT "qrcode_files_qrcode_id_fk" FOREIGN KEY ("qrcode_id") REFERENCES "public"."qrcode" ("id") | 
				
			||||
 | 
					); | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode_files"."qrcode_id" IS '关联二维码ID'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode_files"."file_name" IS '文件名'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode_files"."file_size" IS '文件大小(byte)'; | 
				
			||||
 | 
					COMMENT ON COLUMN "public"."qrcode_files"."file_url" IS '文件存储链接'; | 
				
			||||
@ -0,0 +1,19 @@ | 
				
			|||||
 | 
					{ | 
				
			||||
 | 
					  "presets": [ | 
				
			||||
 | 
					    "@babel/preset-react", | 
				
			||||
 | 
					    "@babel/preset-env" | 
				
			||||
 | 
					     | 
				
			||||
 | 
					  ], | 
				
			||||
 | 
					  "plugins": [ | 
				
			||||
 | 
					    "@babel/plugin-proposal-class-properties", | 
				
			||||
 | 
					    "@babel/plugin-proposal-object-rest-spread", | 
				
			||||
 | 
					    ["import", { | 
				
			||||
 | 
					      "libraryName": "antd", | 
				
			||||
 | 
					      "libraryDirectory": "es" | 
				
			||||
 | 
					       | 
				
			||||
 | 
					    }] | 
				
			||||
 | 
					  ], | 
				
			||||
 | 
					  "env": { | 
				
			||||
 | 
					    "development": {} | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,23 @@ | 
				
			|||||
 | 
					{ | 
				
			||||
 | 
					   "version": "0.2.0", | 
				
			||||
 | 
					   "configurations": [ | 
				
			||||
 | 
					      { | 
				
			||||
 | 
					         "name": "Server", | 
				
			||||
 | 
					         "type": "node", | 
				
			||||
 | 
					         "request": "launch", | 
				
			||||
 | 
					         "program": "${workspaceRoot}/server.js", | 
				
			||||
 | 
					         "args": [ | 
				
			||||
 | 
					            "-u http://127.0.0.1:4900", | 
				
			||||
 | 
					            //阿里OSS | 
				
			||||
 | 
					            "--aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw", | 
				
			||||
 | 
					            "--aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv", | 
				
			||||
 | 
					            "--aliOssBucket test-c371", | 
				
			||||
 | 
					            "--aliOssRegion oss-cn-hangzhou", | 
				
			||||
 | 
					         ], | 
				
			||||
 | 
					         "outputCapture": "std", | 
				
			||||
 | 
					         "env": { | 
				
			||||
 | 
					            "NODE_ENV": "development" | 
				
			||||
 | 
					         } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   ] | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,4 @@ | 
				
			|||||
 | 
					// 将设置放入此文件中以覆盖默认值和用户设置。 | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					    // "editor.fontSize": 16, | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,56 @@ | 
				
			|||||
 | 
					#FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2 | 
				
			||||
 | 
					FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2 | 
				
			||||
 | 
					COPY ./web/  /var/app | 
				
			||||
 | 
					WORKDIR /var/app | 
				
			||||
 | 
					EXPOSE 8080 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					RUN apk update && apk add --no-cache \ | 
				
			||||
 | 
					        sudo \ | 
				
			||||
 | 
					        curl \ | 
				
			||||
 | 
					        build-base \ | 
				
			||||
 | 
					        g++ \ | 
				
			||||
 | 
					        libpng \ | 
				
			||||
 | 
					        libpng-dev \ | 
				
			||||
 | 
					        jpeg-dev \ | 
				
			||||
 | 
					        pango-dev \ | 
				
			||||
 | 
					        cairo-dev \ | 
				
			||||
 | 
					        giflib-dev \ | 
				
			||||
 | 
					        python \ | 
				
			||||
 | 
					        ; | 
				
			||||
 | 
					RUN npm config set registry=https://nexus.ngaiot.com/repository/fs-npm/ | 
				
			||||
 | 
					RUN npm cache clean -f | 
				
			||||
 | 
					#RUN npm install -g node-gyp | 
				
			||||
 | 
					RUN rm -rf package-lock.json | 
				
			||||
 | 
					RUN npm install  --registry https://nexus.ngaiot.com/repository/fs-npm/ | 
				
			||||
 | 
					RUN npm run build | 
				
			||||
 | 
					RUN rm  -rf client/src | 
				
			||||
 | 
					RUN rm  -rf node_modules | 
				
			||||
 | 
					RUN npm install --production --registry https://nexus.ngaiot.com/repository/fs-npm/ | 
				
			||||
 | 
					#RUN npm cache clean -f && npm install --production --force --registry http://10.8.30.22:7000 | 
				
			||||
 | 
					CMD ["-u", "http://localhost:8088"] | 
				
			||||
 | 
					ENTRYPOINT [ "node", "server.js" ] | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12-dev as builder | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# COPY . /var/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# WORKDIR /var/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# EXPOSE 8080 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# RUN npm config set registry=http://10.8.30.22:7000 | 
				
			||||
 | 
					# RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json | 
				
			||||
 | 
					# RUN npm cache clean -f | 
				
			||||
 | 
					# RUN rm -rf package-lock.json | 
				
			||||
 | 
					# RUN npm install --registry http://10.8.30.22:7000 | 
				
			||||
 | 
					# RUN npm run build | 
				
			||||
 | 
					# RUN rm  -rf client/src | 
				
			||||
 | 
					# RUN rm  -rf node_modules | 
				
			||||
 | 
					# RUN npm install --production --force --registry http://10.8.30.22:7000 | 
				
			||||
 | 
					# FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# COPY --from=builder --chown=node /var/app  /home/node/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# WORKDIR /home/node/app | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					# CMD ["node", "server.js"] | 
				
			||||
@ -0,0 +1,370 @@ | 
				
			|||||
 | 
					*{margin: 0;padding: 0;list-style: none;} | 
				
			||||
 | 
					/* | 
				
			||||
 | 
					KISSY CSS Reset | 
				
			||||
 | 
					理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。 | 
				
			||||
 | 
					2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。 | 
				
			||||
 | 
					3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。 | 
				
			||||
 | 
					特色:1. 适应中文;2. 基于最新主流浏览器。 | 
				
			||||
 | 
					维护:玉伯<lifesinger@gmail.com>, 正淳<ragecarrier@gmail.com> | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** 清除内外边距 **/ | 
				
			||||
 | 
					body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */ | 
				
			||||
 | 
					dl, dt, dd, ul, ol, li, /* list elements 列表元素 */ | 
				
			||||
 | 
					pre, /* text formatting elements 文本格式元素 */ | 
				
			||||
 | 
					form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */ | 
				
			||||
 | 
					th, td /* table elements 表格元素 */ { | 
				
			||||
 | 
					  margin: 0; | 
				
			||||
 | 
					  padding: 0; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** 设置默认字体 **/ | 
				
			||||
 | 
					body, | 
				
			||||
 | 
					button, input, select, textarea /* for ie */ { | 
				
			||||
 | 
					  font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					h1, h2, h3, h4, h5, h6 { font-size: 100%; } | 
				
			||||
 | 
					address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */ | 
				
			||||
 | 
					code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */ | 
				
			||||
 | 
					small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** 重置列表元素 **/ | 
				
			||||
 | 
					ul, ol { list-style: none; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** 重置文本格式元素 **/ | 
				
			||||
 | 
					a { text-decoration: none; } | 
				
			||||
 | 
					a:hover { text-decoration: underline; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** 重置表单元素 **/ | 
				
			||||
 | 
					legend { color: #000; } /* for ie6 */ | 
				
			||||
 | 
					fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */ | 
				
			||||
 | 
					button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */ | 
				
			||||
 | 
					/* 注:optgroup 无法扶正 */ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/** 重置表格元素 **/ | 
				
			||||
 | 
					table { border-collapse: collapse; border-spacing: 0; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					/* 清除浮动 */ | 
				
			||||
 | 
					.ks-clear:after, .clear:after { | 
				
			||||
 | 
					  content: '\20'; | 
				
			||||
 | 
					  display: block; | 
				
			||||
 | 
					  height: 0; | 
				
			||||
 | 
					  clear: both; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					.ks-clear, .clear { | 
				
			||||
 | 
					  *zoom: 1; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.main { | 
				
			||||
 | 
					  padding: 30px 100px; | 
				
			||||
 | 
					width: 960px; | 
				
			||||
 | 
					margin: 0 auto; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					.main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.helps{margin-top:40px;} | 
				
			||||
 | 
					.helps pre{ | 
				
			||||
 | 
					  padding:20px; | 
				
			||||
 | 
					  margin:10px 0; | 
				
			||||
 | 
					  border:solid 1px #e7e1cd; | 
				
			||||
 | 
					  background-color: #fffdef; | 
				
			||||
 | 
					  overflow: auto; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon_lists{ | 
				
			||||
 | 
					  width: 100% !important; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon_lists li{ | 
				
			||||
 | 
					  float:left; | 
				
			||||
 | 
					  width: 100px; | 
				
			||||
 | 
					  height:180px; | 
				
			||||
 | 
					  text-align: center; | 
				
			||||
 | 
					  list-style: none !important; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					.icon_lists .icon{ | 
				
			||||
 | 
					  font-size: 42px; | 
				
			||||
 | 
					  line-height: 100px; | 
				
			||||
 | 
					  margin: 10px 0; | 
				
			||||
 | 
					  color:#333; | 
				
			||||
 | 
					  -webkit-transition: font-size 0.25s ease-out 0s; | 
				
			||||
 | 
					  -moz-transition: font-size 0.25s ease-out 0s; | 
				
			||||
 | 
					  transition: font-size 0.25s ease-out 0s; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					.icon_lists .icon:hover{ | 
				
			||||
 | 
					  font-size: 100px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown { | 
				
			||||
 | 
					  color: #666; | 
				
			||||
 | 
					  font-size: 14px; | 
				
			||||
 | 
					  line-height: 1.8; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.highlight { | 
				
			||||
 | 
					  line-height: 1.5; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown img { | 
				
			||||
 | 
					  vertical-align: middle; | 
				
			||||
 | 
					  max-width: 100%; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h1 { | 
				
			||||
 | 
					  color: #404040; | 
				
			||||
 | 
					  font-weight: 500; | 
				
			||||
 | 
					  line-height: 40px; | 
				
			||||
 | 
					  margin-bottom: 24px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h2, | 
				
			||||
 | 
					.markdown h3, | 
				
			||||
 | 
					.markdown h4, | 
				
			||||
 | 
					.markdown h5, | 
				
			||||
 | 
					.markdown h6 { | 
				
			||||
 | 
					  color: #404040; | 
				
			||||
 | 
					  margin: 1.6em 0 0.6em 0; | 
				
			||||
 | 
					  font-weight: 500; | 
				
			||||
 | 
					  clear: both; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h1 { | 
				
			||||
 | 
					  font-size: 28px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h2 { | 
				
			||||
 | 
					  font-size: 22px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h3 { | 
				
			||||
 | 
					  font-size: 16px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h4 { | 
				
			||||
 | 
					  font-size: 14px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h5 { | 
				
			||||
 | 
					  font-size: 12px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h6 { | 
				
			||||
 | 
					  font-size: 12px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown hr { | 
				
			||||
 | 
					  height: 1px; | 
				
			||||
 | 
					  border: 0; | 
				
			||||
 | 
					  background: #e9e9e9; | 
				
			||||
 | 
					  margin: 16px 0; | 
				
			||||
 | 
					  clear: both; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown p, | 
				
			||||
 | 
					.markdown pre { | 
				
			||||
 | 
					  margin: 1em 0; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > p, | 
				
			||||
 | 
					.markdown > blockquote, | 
				
			||||
 | 
					.markdown > .highlight, | 
				
			||||
 | 
					.markdown > ol, | 
				
			||||
 | 
					.markdown > ul { | 
				
			||||
 | 
					  width: 80%; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown ul > li { | 
				
			||||
 | 
					  list-style: circle; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > ul li, | 
				
			||||
 | 
					.markdown blockquote ul > li { | 
				
			||||
 | 
					  margin-left: 20px; | 
				
			||||
 | 
					  padding-left: 4px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > ul li p, | 
				
			||||
 | 
					.markdown > ol li p { | 
				
			||||
 | 
					  margin: 0.6em 0; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown ol > li { | 
				
			||||
 | 
					  list-style: decimal; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > ol li, | 
				
			||||
 | 
					.markdown blockquote ol > li { | 
				
			||||
 | 
					  margin-left: 20px; | 
				
			||||
 | 
					  padding-left: 4px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown code { | 
				
			||||
 | 
					  margin: 0 3px; | 
				
			||||
 | 
					  padding: 0 5px; | 
				
			||||
 | 
					  background: #eee; | 
				
			||||
 | 
					  border-radius: 3px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown pre { | 
				
			||||
 | 
					  border-radius: 6px; | 
				
			||||
 | 
					  background: #f7f7f7; | 
				
			||||
 | 
					  padding: 20px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown pre code { | 
				
			||||
 | 
					  border: none; | 
				
			||||
 | 
					  background: #f7f7f7; | 
				
			||||
 | 
					  margin: 0; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown strong, | 
				
			||||
 | 
					.markdown b { | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > table { | 
				
			||||
 | 
					  border-collapse: collapse; | 
				
			||||
 | 
					  border-spacing: 0px; | 
				
			||||
 | 
					  empty-cells: show; | 
				
			||||
 | 
					  border: 1px solid #e9e9e9; | 
				
			||||
 | 
					  width: 95%; | 
				
			||||
 | 
					  margin-bottom: 24px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > table th { | 
				
			||||
 | 
					  white-space: nowrap; | 
				
			||||
 | 
					  color: #333; | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > table th, | 
				
			||||
 | 
					.markdown > table td { | 
				
			||||
 | 
					  border: 1px solid #e9e9e9; | 
				
			||||
 | 
					  padding: 8px 16px; | 
				
			||||
 | 
					  text-align: left; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > table th { | 
				
			||||
 | 
					  background: #F7F7F7; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown blockquote { | 
				
			||||
 | 
					  font-size: 90%; | 
				
			||||
 | 
					  color: #999; | 
				
			||||
 | 
					  border-left: 4px solid #e9e9e9; | 
				
			||||
 | 
					  padding-left: 0.8em; | 
				
			||||
 | 
					  margin: 1em 0; | 
				
			||||
 | 
					  font-style: italic; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown blockquote p { | 
				
			||||
 | 
					  margin: 0; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown .anchor { | 
				
			||||
 | 
					  opacity: 0; | 
				
			||||
 | 
					  transition: opacity 0.3s ease; | 
				
			||||
 | 
					  margin-left: 8px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown .waiting { | 
				
			||||
 | 
					  color: #ccc; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown h1:hover .anchor, | 
				
			||||
 | 
					.markdown h2:hover .anchor, | 
				
			||||
 | 
					.markdown h3:hover .anchor, | 
				
			||||
 | 
					.markdown h4:hover .anchor, | 
				
			||||
 | 
					.markdown h5:hover .anchor, | 
				
			||||
 | 
					.markdown h6:hover .anchor { | 
				
			||||
 | 
					  opacity: 1; | 
				
			||||
 | 
					  display: inline-block; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.markdown > br, | 
				
			||||
 | 
					.markdown > p > br { | 
				
			||||
 | 
					  clear: both; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs { | 
				
			||||
 | 
					  display: block; | 
				
			||||
 | 
					  background: white; | 
				
			||||
 | 
					  padding: 0.5em; | 
				
			||||
 | 
					  color: #333333; | 
				
			||||
 | 
					  overflow-x: auto; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-comment, | 
				
			||||
 | 
					.hljs-meta { | 
				
			||||
 | 
					  color: #969896; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-string, | 
				
			||||
 | 
					.hljs-variable, | 
				
			||||
 | 
					.hljs-template-variable, | 
				
			||||
 | 
					.hljs-strong, | 
				
			||||
 | 
					.hljs-emphasis, | 
				
			||||
 | 
					.hljs-quote { | 
				
			||||
 | 
					  color: #df5000; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-keyword, | 
				
			||||
 | 
					.hljs-selector-tag, | 
				
			||||
 | 
					.hljs-type { | 
				
			||||
 | 
					  color: #a71d5d; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-literal, | 
				
			||||
 | 
					.hljs-symbol, | 
				
			||||
 | 
					.hljs-bullet, | 
				
			||||
 | 
					.hljs-attribute { | 
				
			||||
 | 
					  color: #0086b3; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-section, | 
				
			||||
 | 
					.hljs-name { | 
				
			||||
 | 
					  color: #63a35c; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-tag { | 
				
			||||
 | 
					  color: #333333; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-title, | 
				
			||||
 | 
					.hljs-attr, | 
				
			||||
 | 
					.hljs-selector-id, | 
				
			||||
 | 
					.hljs-selector-class, | 
				
			||||
 | 
					.hljs-selector-attr, | 
				
			||||
 | 
					.hljs-selector-pseudo { | 
				
			||||
 | 
					  color: #795da3; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-addition { | 
				
			||||
 | 
					  color: #55a532; | 
				
			||||
 | 
					  background-color: #eaffea; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-deletion { | 
				
			||||
 | 
					  color: #bd2c00; | 
				
			||||
 | 
					  background-color: #ffecec; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.hljs-link { | 
				
			||||
 | 
					  text-decoration: underline; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					pre{ | 
				
			||||
 | 
					  background: #fff; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
@ -0,0 +1,514 @@ | 
				
			|||||
 | 
					
 | 
				
			||||
 | 
					<!DOCTYPE html> | 
				
			||||
 | 
					<html> | 
				
			||||
 | 
					<head> | 
				
			||||
 | 
					    <meta charset="utf-8"/> | 
				
			||||
 | 
					    <title>IconFont</title> | 
				
			||||
 | 
					    <link rel="stylesheet" href="demo.css"> | 
				
			||||
 | 
					    <link rel="stylesheet" href="iconfont.css"> | 
				
			||||
 | 
					</head> | 
				
			||||
 | 
					<body> | 
				
			||||
 | 
					    <div class="main markdown"> | 
				
			||||
 | 
					        <h1>IconFont 图标</h1> | 
				
			||||
 | 
					        <ul class="icon_lists clear"> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-liuliang"></i> | 
				
			||||
 | 
					                    <div class="name">流量</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-liuliang</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-iconfontditie"></i> | 
				
			||||
 | 
					                    <div class="name">轻轨</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-iconfontditie</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-fengsu3"></i> | 
				
			||||
 | 
					                    <div class="name">风速3</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-fengsu3</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-calendar"></i> | 
				
			||||
 | 
					                    <div class="name">calendar</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-calendar</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-box"></i> | 
				
			||||
 | 
					                    <div class="name">box</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-box</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shenheshibai"></i> | 
				
			||||
 | 
					                    <div class="name">审核失败</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shenheshibai</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-slope"></i> | 
				
			||||
 | 
					                    <div class="name">边坡</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-slope</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-icon2"></i> | 
				
			||||
 | 
					                    <div class="name">公路</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-icon2</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-gnsscaidian"></i> | 
				
			||||
 | 
					                    <div class="name">GNSS采点</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-gnsscaidian</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-chuanganqishebei"></i> | 
				
			||||
 | 
					                    <div class="name">传感器设备</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-chuanganqishebei</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-dianliuchuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">电流传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-dianliuchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-dianyachuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">电压传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-dianyachuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-wenduchuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">温度传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-wenduchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-xinjian"></i> | 
				
			||||
 | 
					                    <div class="name">新建</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-xinjian</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-handong"></i> | 
				
			||||
 | 
					                    <div class="name">涵洞</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-handong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-guanwanggongcheng"></i> | 
				
			||||
 | 
					                    <div class="name">管网工程</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-guanwanggongcheng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shenhe"></i> | 
				
			||||
 | 
					                    <div class="name">审核</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shenhe</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-zhihuishequ"></i> | 
				
			||||
 | 
					                    <div class="name">智慧城市</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-zhihuishequ</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-bianpoweiyi"></i> | 
				
			||||
 | 
					                    <div class="name">边坡位移</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-bianpoweiyi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-jianzhu"></i> | 
				
			||||
 | 
					                    <div class="name">建筑</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-jianzhu</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-chuguan"></i> | 
				
			||||
 | 
					                    <div class="name">储罐</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-chuguan</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-suidao"></i> | 
				
			||||
 | 
					                    <div class="name">隧道</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-suidao</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-data"></i> | 
				
			||||
 | 
					                    <div class="name">data</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-data</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-kuangshankaicai"></i> | 
				
			||||
 | 
					                    <div class="name">矿山开采</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-kuangshankaicai</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-wangluo"></i> | 
				
			||||
 | 
					                    <div class="name">网络</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-wangluo</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-jiankong"></i> | 
				
			||||
 | 
					                    <div class="name">监控</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-jiankong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-dashuju"></i> | 
				
			||||
 | 
					                    <div class="name">大数据</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-dashuju</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shuju"></i> | 
				
			||||
 | 
					                    <div class="name">数据库</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shuju</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shenhechenggong"></i> | 
				
			||||
 | 
					                    <div class="name">审核成功</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shenhechenggong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-jiankong1"></i> | 
				
			||||
 | 
					                    <div class="name">监控</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-jiankong1</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-wangluoxitong"></i> | 
				
			||||
 | 
					                    <div class="name">网络系统</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-wangluoxitong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-dingwei"></i> | 
				
			||||
 | 
					                    <div class="name">定位</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-dingwei</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-xitongyunzhuanqingkuang"></i> | 
				
			||||
 | 
					                    <div class="name">系统运转情况</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-xitongyunzhuanqingkuang</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-chakan"></i> | 
				
			||||
 | 
					                    <div class="name">查看</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-chakan</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-lianjie"></i> | 
				
			||||
 | 
					                    <div class="name">链接</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-lianjie</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shujudaochu-01"></i> | 
				
			||||
 | 
					                    <div class="name">数据导出-01</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shujudaochu-01</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-xitongzhuangtai"></i> | 
				
			||||
 | 
					                    <div class="name">系统状态</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-xitongzhuangtai</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-xiaofeimingxidan"></i> | 
				
			||||
 | 
					                    <div class="name">消费明细单</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-xiaofeimingxidan</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-SQLshenhe"></i> | 
				
			||||
 | 
					                    <div class="name">SQL审核</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-SQLshenhe</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-aislogo"></i> | 
				
			||||
 | 
					                    <div class="name">aislogo</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-aislogo</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-qiao"></i> | 
				
			||||
 | 
					                    <div class="name">桥</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-qiao</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-tashiqizhongji"></i> | 
				
			||||
 | 
					                    <div class="name">塔式起重机</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-tashiqizhongji</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-dwggeshi"></i> | 
				
			||||
 | 
					                    <div class="name">dwg格式</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-dwggeshi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-luyouqi"></i> | 
				
			||||
 | 
					                    <div class="name">路由器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-luyouqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-anzhuangshigong-xianxing"></i> | 
				
			||||
 | 
					                    <div class="name">244安装、施工-线性</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-anzhuangshigong-xianxing</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shaixuanguolv"></i> | 
				
			||||
 | 
					                    <div class="name">245筛选过滤</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shaixuanguolv</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-anzhuangshigong"></i> | 
				
			||||
 | 
					                    <div class="name">244安装、施工</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-anzhuangshigong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-tiaoxingtu-xianxing"></i> | 
				
			||||
 | 
					                    <div class="name">408条形图-线性</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-tiaoxingtu-xianxing</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-zhexiantu-xianxing"></i> | 
				
			||||
 | 
					                    <div class="name">409折线图-线性</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-zhexiantu-xianxing</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-tieta"></i> | 
				
			||||
 | 
					                    <div class="name">铁塔</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-tieta</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_wendangtxt"></i> | 
				
			||||
 | 
					                    <div class="name">800格式_文档txt</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_wendangtxt</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_wendangdoc"></i> | 
				
			||||
 | 
					                    <div class="name">801格式_文档doc</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_wendangdoc</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_wendangpdf"></i> | 
				
			||||
 | 
					                    <div class="name">807格式_文档pdf</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_wendangpdf</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_wendangxls"></i> | 
				
			||||
 | 
					                    <div class="name">803格式_文档xls</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_wendangxls</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_tongyongwendang"></i> | 
				
			||||
 | 
					                    <div class="name">819格式_通用文档</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_tongyongwendang</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_shipinmp"></i> | 
				
			||||
 | 
					                    <div class="name">840格式_视频mp4</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_shipinmp</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_tupianjpg"></i> | 
				
			||||
 | 
					                    <div class="name">860格式_图片jpg</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_tupianjpg</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-geshi_tupianpng"></i> | 
				
			||||
 | 
					                    <div class="name">865格式_图片png</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-geshi_tupianpng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-guangzhaochuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">光照传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-guangzhaochuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-building"></i> | 
				
			||||
 | 
					                    <div class="name">建筑</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-building</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-yanwuchuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">烟雾传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-yanwuchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shizheng"></i> | 
				
			||||
 | 
					                    <div class="name">市政</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shizheng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-chuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-chuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-WSD"></i> | 
				
			||||
 | 
					                    <div class="name">温湿度传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-WSD</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-yalichuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">压力传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-yalichuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-yinglichuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">应力传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-yinglichuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-chenjiangchuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">沉降传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-chenjiangchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-yalichuanganqi1"></i> | 
				
			||||
 | 
					                    <div class="name">压力传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-yalichuanganqi1</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-YWC"></i> | 
				
			||||
 | 
					                    <div class="name">液位传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-YWC</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-computer"></i> | 
				
			||||
 | 
					                    <div class="name">computer</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-computer</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-empty"></i> | 
				
			||||
 | 
					                    <div class="name">empty</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-empty</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-offline"></i> | 
				
			||||
 | 
					                    <div class="name">offline</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-offline</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-daba"></i> | 
				
			||||
 | 
					                    <div class="name">大坝</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-daba</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shenbuweiyi"></i> | 
				
			||||
 | 
					                    <div class="name">深部位移</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shenbuweiyi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-maosuochuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">锚索传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-maosuochuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-yuliangchuanganqi"></i> | 
				
			||||
 | 
					                    <div class="name">雨量传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-yuliangchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-weiyiji"></i> | 
				
			||||
 | 
					                    <div class="name">位移计</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-weiyiji</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-qixiangzhan_"></i> | 
				
			||||
 | 
					                    <div class="name">气象站_1</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-qixiangzhan_</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc icon-shenjikeng"></i> | 
				
			||||
 | 
					                    <div class="name">深基坑</div> | 
				
			||||
 | 
					                    <div class="fontclass">.icon-shenjikeng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					        </ul> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <h2 id="font-class-">font-class引用</h2> | 
				
			||||
 | 
					        <hr> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <p>font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。</p> | 
				
			||||
 | 
					        <p>与unicode使用方式相比,具有如下特点:</p> | 
				
			||||
 | 
					        <ul> | 
				
			||||
 | 
					        <li>兼容性良好,支持ie8+,及所有现代浏览器。</li> | 
				
			||||
 | 
					        <li>相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。</li> | 
				
			||||
 | 
					        <li>因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。</li> | 
				
			||||
 | 
					        <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li> | 
				
			||||
 | 
					        </ul> | 
				
			||||
 | 
					        <p>使用步骤如下:</p> | 
				
			||||
 | 
					        <h3 id="-fontclass-">第一步:引入项目下面生成的fontclass代码:</h3> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript"><span class="hljs-comment"><link rel="stylesheet" type="text/css" href="./iconfont.css"></span></code></pre> | 
				
			||||
 | 
					        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3> | 
				
			||||
 | 
					        <pre><code class="lang-css hljs"><<span class="hljs-selector-tag">i</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">sc</span> <span class="hljs-selector-tag">icon-xxx</span>"></<span class="hljs-selector-tag">i</span>></code></pre> | 
				
			||||
 | 
					        <blockquote> | 
				
			||||
 | 
					        <p>"sc"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p> | 
				
			||||
 | 
					        </blockquote> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					</body> | 
				
			||||
 | 
					</html> | 
				
			||||
@ -0,0 +1,695 @@ | 
				
			|||||
 | 
					
 | 
				
			||||
 | 
					<!DOCTYPE html> | 
				
			||||
 | 
					<html> | 
				
			||||
 | 
					<head> | 
				
			||||
 | 
					    <meta charset="utf-8"/> | 
				
			||||
 | 
					    <title>IconFont</title> | 
				
			||||
 | 
					    <link rel="stylesheet" href="demo.css"> | 
				
			||||
 | 
					    <script src="iconfont.js"></script> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <style type="text/css"> | 
				
			||||
 | 
					        .icon { | 
				
			||||
 | 
					          /* 通过设置 font-size 来改变图标大小 */ | 
				
			||||
 | 
					          width: 1em; height: 1em; | 
				
			||||
 | 
					          /* 图标和文字相邻时,垂直对齐 */ | 
				
			||||
 | 
					          vertical-align: -0.15em; | 
				
			||||
 | 
					          /* 通过设置 color 来改变 SVG 的颜色/fill */ | 
				
			||||
 | 
					          fill: currentColor; | 
				
			||||
 | 
					          /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 | 
				
			||||
 | 
					             normalize.css 中也包含这行 */ | 
				
			||||
 | 
					          overflow: hidden; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    </style> | 
				
			||||
 | 
					</head> | 
				
			||||
 | 
					<body> | 
				
			||||
 | 
					    <div class="main markdown"> | 
				
			||||
 | 
					        <h1>IconFont 图标</h1> | 
				
			||||
 | 
					        <ul class="icon_lists clear"> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-liuliang"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">流量</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-liuliang</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-iconfontditie"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">轻轨</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-iconfontditie</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-fengsu3"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">风速3</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-fengsu3</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-calendar"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">calendar</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-calendar</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-box"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">box</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-box</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shenheshibai"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">审核失败</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shenheshibai</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-slope"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">边坡</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-slope</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-icon2"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">公路</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-icon2</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-gnsscaidian"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">GNSS采点</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-gnsscaidian</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-chuanganqishebei"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">传感器设备</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-chuanganqishebei</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-dianliuchuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">电流传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-dianliuchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-dianyachuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">电压传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-dianyachuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-wenduchuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">温度传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-wenduchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-xinjian"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">新建</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-xinjian</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-handong"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">涵洞</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-handong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-guanwanggongcheng"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">管网工程</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-guanwanggongcheng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shenhe"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">审核</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shenhe</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-zhihuishequ"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">智慧城市</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-zhihuishequ</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-bianpoweiyi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">边坡位移</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-bianpoweiyi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-jianzhu"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">建筑</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-jianzhu</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-chuguan"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">储罐</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-chuguan</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-suidao"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">隧道</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-suidao</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-data"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">data</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-data</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-kuangshankaicai"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">矿山开采</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-kuangshankaicai</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-wangluo"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">网络</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-wangluo</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-jiankong"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">监控</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-jiankong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-dashuju"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">大数据</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-dashuju</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shuju"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">数据库</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shuju</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shenhechenggong"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">审核成功</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shenhechenggong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-jiankong1"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">监控</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-jiankong1</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-wangluoxitong"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">网络系统</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-wangluoxitong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-dingwei"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">定位</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-dingwei</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-xitongyunzhuanqingkuang"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">系统运转情况</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-xitongyunzhuanqingkuang</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-chakan"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">查看</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-chakan</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-lianjie"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">链接</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-lianjie</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shujudaochu-01"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">数据导出-01</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shujudaochu-01</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-xitongzhuangtai"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">系统状态</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-xitongzhuangtai</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-xiaofeimingxidan"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">消费明细单</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-xiaofeimingxidan</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-SQLshenhe"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">SQL审核</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-SQLshenhe</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-aislogo"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">aislogo</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-aislogo</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-qiao"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">桥</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-qiao</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-tashiqizhongji"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">塔式起重机</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-tashiqizhongji</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-dwggeshi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">dwg格式</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-dwggeshi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-luyouqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">路由器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-luyouqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-anzhuangshigong-xianxing"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">244安装、施工-线性</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-anzhuangshigong-xianxing</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shaixuanguolv"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">245筛选过滤</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shaixuanguolv</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-anzhuangshigong"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">244安装、施工</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-anzhuangshigong</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-tiaoxingtu-xianxing"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">408条形图-线性</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-tiaoxingtu-xianxing</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-zhexiantu-xianxing"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">409折线图-线性</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-zhexiantu-xianxing</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-tieta"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">铁塔</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-tieta</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_wendangtxt"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">800格式_文档txt</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_wendangtxt</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_wendangdoc"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">801格式_文档doc</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_wendangdoc</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_wendangpdf"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">807格式_文档pdf</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_wendangpdf</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_wendangxls"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">803格式_文档xls</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_wendangxls</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_tongyongwendang"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">819格式_通用文档</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_tongyongwendang</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_shipinmp"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">840格式_视频mp4</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_shipinmp</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_tupianjpg"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">860格式_图片jpg</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_tupianjpg</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-geshi_tupianpng"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">865格式_图片png</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-geshi_tupianpng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-guangzhaochuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">光照传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-guangzhaochuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-building"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">建筑</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-building</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-yanwuchuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">烟雾传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-yanwuchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shizheng"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">市政</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shizheng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-chuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-chuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-WSD"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">温湿度传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-WSD</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-yalichuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">压力传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-yalichuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-yinglichuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">应力传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-yinglichuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-chenjiangchuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">沉降传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-chenjiangchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-yalichuanganqi1"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">压力传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-yalichuanganqi1</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-YWC"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">液位传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-YWC</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-computer"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">computer</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-computer</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-empty"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">empty</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-empty</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-offline"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">offline</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-offline</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-daba"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">大坝</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-daba</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shenbuweiyi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">深部位移</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shenbuweiyi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-maosuochuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">锚索传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-maosuochuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-yuliangchuanganqi"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">雨量传感器</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-yuliangchuanganqi</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-weiyiji"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">位移计</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-weiyiji</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-qixiangzhan_"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">气象站_1</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-qixiangzhan_</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                    <svg class="icon" aria-hidden="true"> | 
				
			||||
 | 
					                        <use xlink:href="#icon-shenjikeng"></use> | 
				
			||||
 | 
					                    </svg> | 
				
			||||
 | 
					                    <div class="name">深基坑</div> | 
				
			||||
 | 
					                    <div class="fontclass">#icon-shenjikeng</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					        </ul> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <h2 id="symbol-">symbol引用</h2> | 
				
			||||
 | 
					        <hr> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a> | 
				
			||||
 | 
					        这种用法其实是做了一个svg的集合,与另外两种相比具有如下特点:</p> | 
				
			||||
 | 
					        <ul> | 
				
			||||
 | 
					          <li>支持多色图标了,不再受单色限制。</li> | 
				
			||||
 | 
					          <li>通过一些技巧,支持像字体那样,通过<code>font-size</code>,<code>color</code>来调整样式。</li> | 
				
			||||
 | 
					          <li>兼容性较差,支持 ie9+,及现代浏览器。</li> | 
				
			||||
 | 
					          <li>浏览器渲染svg的性能一般,还不如png。</li> | 
				
			||||
 | 
					        </ul> | 
				
			||||
 | 
					        <p>使用步骤如下:</p> | 
				
			||||
 | 
					        <h3 id="-symbol-">第一步:引入项目下面生成的symbol代码:</h3> | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript"><span class="hljs-comment"><script src="./iconfont.js"></script></span></code></pre> | 
				
			||||
 | 
					        <h3 id="-css-">第二步:加入通用css代码(引入一次就行):</h3> | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript"><style type=<span class="hljs-string">"text/css"</span>> | 
				
			||||
 | 
					.icon { | 
				
			||||
 | 
					   width: <span class="hljs-number">1</span>em; height: <span class="hljs-number">1</span>em; | 
				
			||||
 | 
					   vertical-align: <span class="hljs-number">-0.15</span>em; | 
				
			||||
 | 
					   fill: currentColor; | 
				
			||||
 | 
					   overflow: hidden; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					<<span class="hljs-regexp">/style></span></code></pre> | 
				
			||||
 | 
					        <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3> | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript"><svg <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"icon"</span> aria-hidden=<span class="hljs-string">"true"</span>><span class="xml"><span class="hljs-tag"> | 
				
			||||
 | 
					  <<span class="hljs-name">use</span> <span class="hljs-attr">xlink:href</span>=<span class="hljs-string">"#icon-xxx"</span>></span><span class="hljs-tag"></<span class="hljs-name">use</span>></span> | 
				
			||||
 | 
					</span><<span class="hljs-regexp">/svg> | 
				
			||||
 | 
					        </span></code></pre> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					</body> | 
				
			||||
 | 
					</html> | 
				
			||||
@ -0,0 +1,552 @@ | 
				
			|||||
 | 
					
 | 
				
			||||
 | 
					<!DOCTYPE html> | 
				
			||||
 | 
					<html> | 
				
			||||
 | 
					<head> | 
				
			||||
 | 
					    <meta charset="utf-8"/> | 
				
			||||
 | 
					    <title>IconFont</title> | 
				
			||||
 | 
					    <link rel="stylesheet" href="demo.css"> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <style type="text/css"> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        @font-face {font-family: "sc"; | 
				
			||||
 | 
					          src: url('iconfont.eot'); /* IE9*/ | 
				
			||||
 | 
					          src: url('iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */ | 
				
			||||
 | 
					          url('iconfont.woff') format('woff'), /* chrome, firefox */ | 
				
			||||
 | 
					          url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ | 
				
			||||
 | 
					          url('iconfont.svg#sc') format('svg'); /* iOS 4.1- */ | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        .sc { | 
				
			||||
 | 
					          font-family:"sc" !important; | 
				
			||||
 | 
					          font-size:16px; | 
				
			||||
 | 
					          font-style:normal; | 
				
			||||
 | 
					          -webkit-font-smoothing: antialiased; | 
				
			||||
 | 
					          -webkit-text-stroke-width: 0.2px; | 
				
			||||
 | 
					          -moz-osx-font-smoothing: grayscale; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    </style> | 
				
			||||
 | 
					</head> | 
				
			||||
 | 
					<body> | 
				
			||||
 | 
					    <div class="main markdown"> | 
				
			||||
 | 
					        <h1>IconFont 图标</h1> | 
				
			||||
 | 
					        <ul class="icon_lists clear"> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">流量</div> | 
				
			||||
 | 
					                    <div class="code">&#xe602;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">轻轨</div> | 
				
			||||
 | 
					                    <div class="code">&#xe66f;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">风速3</div> | 
				
			||||
 | 
					                    <div class="code">&#xe635;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">calendar</div> | 
				
			||||
 | 
					                    <div class="code">&#xe74a;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">box</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6cb;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">审核失败</div> | 
				
			||||
 | 
					                    <div class="code">&#xe61d;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">边坡</div> | 
				
			||||
 | 
					                    <div class="code">&#xe676;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">公路</div> | 
				
			||||
 | 
					                    <div class="code">&#xe607;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">GNSS采点</div> | 
				
			||||
 | 
					                    <div class="code">&#xe825;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">传感器设备</div> | 
				
			||||
 | 
					                    <div class="code">&#xe612;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">电流传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe62c;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">电压传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe62f;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">温度传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe637;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">新建</div> | 
				
			||||
 | 
					                    <div class="code">&#xe61f;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">涵洞</div> | 
				
			||||
 | 
					                    <div class="code">&#xe89b;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">管网工程</div> | 
				
			||||
 | 
					                    <div class="code">&#xe646;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">审核</div> | 
				
			||||
 | 
					                    <div class="code">&#xe639;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">智慧城市</div> | 
				
			||||
 | 
					                    <div class="code">&#xe600;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">边坡位移</div> | 
				
			||||
 | 
					                    <div class="code">&#xe60a;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">建筑</div> | 
				
			||||
 | 
					                    <div class="code">&#xe65f;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">储罐</div> | 
				
			||||
 | 
					                    <div class="code">&#xe636;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">隧道</div> | 
				
			||||
 | 
					                    <div class="code">&#xe61e;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">data</div> | 
				
			||||
 | 
					                    <div class="code">&#xe757;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">矿山开采</div> | 
				
			||||
 | 
					                    <div class="code">&#xe608;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">网络</div> | 
				
			||||
 | 
					                    <div class="code">&#xe617;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">监控</div> | 
				
			||||
 | 
					                    <div class="code">&#xe619;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">大数据</div> | 
				
			||||
 | 
					                    <div class="code">&#xe61a;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">数据库</div> | 
				
			||||
 | 
					                    <div class="code">&#xe61b;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">审核成功</div> | 
				
			||||
 | 
					                    <div class="code">&#xe627;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">监控</div> | 
				
			||||
 | 
					                    <div class="code">&#xe620;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">网络系统</div> | 
				
			||||
 | 
					                    <div class="code">&#xe62e;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">定位</div> | 
				
			||||
 | 
					                    <div class="code">&#xe630;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">系统运转情况</div> | 
				
			||||
 | 
					                    <div class="code">&#xe631;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">查看</div> | 
				
			||||
 | 
					                    <div class="code">&#xe63e;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">链接</div> | 
				
			||||
 | 
					                    <div class="code">&#xe63f;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">数据导出-01</div> | 
				
			||||
 | 
					                    <div class="code">&#xe640;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">系统状态</div> | 
				
			||||
 | 
					                    <div class="code">&#xe642;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">消费明细单</div> | 
				
			||||
 | 
					                    <div class="code">&#xe643;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">SQL审核</div> | 
				
			||||
 | 
					                    <div class="code">&#xe645;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">aislogo</div> | 
				
			||||
 | 
					                    <div class="code">&#xe648;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">桥</div> | 
				
			||||
 | 
					                    <div class="code">&#xe715;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">塔式起重机</div> | 
				
			||||
 | 
					                    <div class="code">&#xe615;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">dwg格式</div> | 
				
			||||
 | 
					                    <div class="code">&#xe82b;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">路由器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe603;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">244安装、施工-线性</div> | 
				
			||||
 | 
					                    <div class="code">&#xe8d6;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">245筛选过滤</div> | 
				
			||||
 | 
					                    <div class="code">&#xe8d7;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">244安装、施工</div> | 
				
			||||
 | 
					                    <div class="code">&#xe8d8;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">408条形图-线性</div> | 
				
			||||
 | 
					                    <div class="code">&#xe904;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">409折线图-线性</div> | 
				
			||||
 | 
					                    <div class="code">&#xe906;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">铁塔</div> | 
				
			||||
 | 
					                    <div class="code">&#xe605;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">800格式_文档txt</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6b8;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">801格式_文档doc</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6b9;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">807格式_文档pdf</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6bc;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">803格式_文档xls</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6be;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">819格式_通用文档</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6c0;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">840格式_视频mp4</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6c8;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">860格式_图片jpg</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6cc;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">865格式_图片png</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6ce;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">光照传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe638;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">建筑</div> | 
				
			||||
 | 
					                    <div class="code">&#xe61c;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">烟雾传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe610;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">市政</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6ca;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe60f;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">温湿度传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe697;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">压力传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe60e;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">应力传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe611;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">沉降传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe601;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">压力传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe606;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">液位传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe699;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">computer</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6eb;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">empty</div> | 
				
			||||
 | 
					                    <div class="code">&#xe6f7;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">offline</div> | 
				
			||||
 | 
					                    <div class="code">&#xe712;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">大坝</div> | 
				
			||||
 | 
					                    <div class="code">&#xe632;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">深部位移</div> | 
				
			||||
 | 
					                    <div class="code">&#xe613;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">锚索传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe614;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">雨量传感器</div> | 
				
			||||
 | 
					                    <div class="code">&#xe616;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">位移计</div> | 
				
			||||
 | 
					                    <div class="code">&#xe618;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">气象站_1</div> | 
				
			||||
 | 
					                    <div class="code">&#xe60d;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					                <li> | 
				
			||||
 | 
					                <i class="icon sc"></i> | 
				
			||||
 | 
					                    <div class="name">深基坑</div> | 
				
			||||
 | 
					                    <div class="code">&#xe62a;</div> | 
				
			||||
 | 
					                </li> | 
				
			||||
 | 
					             | 
				
			||||
 | 
					        </ul> | 
				
			||||
 | 
					        <h2 id="unicode-">unicode引用</h2> | 
				
			||||
 | 
					        <hr> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <p>unicode是字体在网页端最原始的应用方式,特点是:</p> | 
				
			||||
 | 
					        <ul> | 
				
			||||
 | 
					        <li>兼容性最好,支持ie6+,及所有现代浏览器。</li> | 
				
			||||
 | 
					        <li>支持按字体的方式去动态调整图标大小,颜色等等。</li> | 
				
			||||
 | 
					        <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li> | 
				
			||||
 | 
					        </ul> | 
				
			||||
 | 
					        <blockquote> | 
				
			||||
 | 
					        <p>注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式</p> | 
				
			||||
 | 
					        </blockquote> | 
				
			||||
 | 
					        <p>unicode使用步骤如下:</p> | 
				
			||||
 | 
					        <h3 id="-font-face">第一步:拷贝项目下面生成的font-face</h3> | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript">@font-face { | 
				
			||||
 | 
					  font-family: <span class="hljs-string">'sc'</span>; | 
				
			||||
 | 
					  src: url(<span class="hljs-string">'iconfont.eot'</span>); | 
				
			||||
 | 
					  src: url(<span class="hljs-string">'iconfont.eot?#iefix'</span>) format(<span class="hljs-string">'embedded-opentype'</span>), | 
				
			||||
 | 
					  url(<span class="hljs-string">'iconfont.woff'</span>) format(<span class="hljs-string">'woff'</span>), | 
				
			||||
 | 
					  url(<span class="hljs-string">'iconfont.ttf'</span>) format(<span class="hljs-string">'truetype'</span>), | 
				
			||||
 | 
					  url(<span class="hljs-string">'iconfont.svg#sc'</span>) format(<span class="hljs-string">'svg'</span>); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					</code></pre> | 
				
			||||
 | 
					        <h3 id="-iconfont-">第二步:定义使用iconfont的样式</h3> | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript">.sc{ | 
				
			||||
 | 
					  font-family:<span class="hljs-string">"sc"</span> !important; | 
				
			||||
 | 
					  font-size:<span class="hljs-number">16</span>px;font-style:normal; | 
				
			||||
 | 
					  -webkit-font-smoothing: antialiased; | 
				
			||||
 | 
					  -webkit-text-stroke-width: <span class="hljs-number">0.2</span>px; | 
				
			||||
 | 
					  -moz-osx-font-smoothing: grayscale; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					</code></pre> | 
				
			||||
 | 
					        <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3> | 
				
			||||
 | 
					        <pre><code class="lang-js hljs javascript"><i <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"sc"</span>>&#x33;<span class="xml"><span class="hljs-tag"></<span class="hljs-name">i</span>></span></span></code></pre> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <blockquote> | 
				
			||||
 | 
					        <p>"sc"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。</p> | 
				
			||||
 | 
					        </blockquote> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					</body> | 
				
			||||
 | 
					</html> | 
				
			||||
| 
		 After Width: | Height: | Size: 148 KiB  | 
@ -0,0 +1,521 @@ | 
				
			|||||
 | 
					
 | 
				
			||||
 | 
					@font-face {font-family: "anticon"; | 
				
			||||
 | 
					  src: url('iconfont.eot?t=1494480257283'); /* IE9*/ | 
				
			||||
 | 
					  src: url('iconfont.eot?t=1494480257283#iefix') format('embedded-opentype'), /* IE6-IE8 */ | 
				
			||||
 | 
					  url('iconfont.woff?t=1494480257283') format('woff'), /* chrome, firefox */ | 
				
			||||
 | 
					  url('iconfont.ttf?t=1494480257283') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ | 
				
			||||
 | 
					  url('iconfont.svg?t=1494480257283#anticon') format('svg'); /* iOS 4.1- */ | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.anticon { | 
				
			||||
 | 
					  font-family:"anticon" !important; | 
				
			||||
 | 
					  font-size:16px; | 
				
			||||
 | 
					  font-style:normal; | 
				
			||||
 | 
					  -webkit-font-smoothing: antialiased; | 
				
			||||
 | 
					  -moz-osx-font-smoothing: grayscale; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-stepforward:before { content: "\e600"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-stepbackward:before { content: "\e601"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-forward:before { content: "\e602"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-banckward:before { content: "\e603"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-caretright:before { content: "\e604"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-caretleft:before { content: "\e605"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-caretdown:before { content: "\e606"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-caretup:before { content: "\e607"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rightcircle:before { content: "\e608"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-leftcircle:before { content: "\e609"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-upcircle:before { content: "\e60a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-downcircle:before { content: "\e60b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rightcircleo:before { content: "\e60c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-leftcircleo:before { content: "\e60d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-upcircleo:before { content: "\e60e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-downcircleo:before { content: "\e60f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-verticleleft:before { content: "\e610"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-verticleright:before { content: "\e611"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rollback:before { content: "\e612"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-retweet:before { content: "\e613"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-shrink:before { content: "\e614"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-arrowsalt:before { content: "\e615"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-doubleright:before { content: "\e617"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-doubleleft:before { content: "\e618"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-arrowdown:before { content: "\e619"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-arrowup:before { content: "\e61a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-arrowright:before { content: "\e61b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-arrowleft:before { content: "\e61c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-down:before { content: "\e61d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-up:before { content: "\e61e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-right:before { content: "\e61f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-left:before { content: "\e620"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-minussquareo:before { content: "\e621"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-minuscircle:before { content: "\e622"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-minuscircleo:before { content: "\e623"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-minus:before { content: "\e624"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pluscircleo:before { content: "\e625"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pluscircle:before { content: "\e626"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-plus:before { content: "\e627"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-infocirlce:before { content: "\e628"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-infocirlceo:before { content: "\e629"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-info:before { content: "\e62a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-exclamation:before { content: "\e62b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-exclamationcircle:before { content: "\e62c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-exclamationcircleo:before { content: "\e62d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-closecircle:before { content: "\e62e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-closecircleo:before { content: "\e62f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-checkcircle:before { content: "\e630"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-checkcircleo:before { content: "\e631"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-check:before { content: "\e632"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-close:before { content: "\e633"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-customerservice:before { content: "\e634"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-creditcard:before { content: "\e635"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-codesquareo:before { content: "\e636"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-book:before { content: "\e637"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-barschart:before { content: "\e638"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-bars:before { content: "\e639"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-question:before { content: "\e63a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-questioncircle:before { content: "\e63b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-questioncircleo:before { content: "\e63c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pause:before { content: "\e63d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pausecircle:before { content: "\e63e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pausecircleo:before { content: "\e63f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-clockcircle:before { content: "\e640"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-clockcircleo:before { content: "\e641"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-swap:before { content: "\e642"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-swapleft:before { content: "\e643"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-swapright:before { content: "\e644"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-plussquareo:before { content: "\e645"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-frown:before { content: "\e646"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-menufold:before { content: "\e658"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-mail:before { content: "\e659"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-link:before { content: "\e65b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-areachart:before { content: "\e65c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-linechart:before { content: "\e65d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-home:before { content: "\e65e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-laptop:before { content: "\e65f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-star:before { content: "\e660"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-staro:before { content: "\e661"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-filter:before { content: "\e663"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-meho:before { content: "\e666"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-meh:before { content: "\e667"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-shoppingcart:before { content: "\e668"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-save:before { content: "\e669"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-user:before { content: "\e66a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-videocamera:before { content: "\e66b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-totop:before { content: "\e66c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-team:before { content: "\e66d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-sharealt:before { content: "\e671"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-setting:before { content: "\e672"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-picture:before { content: "\e674"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-phone:before { content: "\e675"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-paperclip:before { content: "\e676"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-notification:before { content: "\e677"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-menuunfold:before { content: "\e679"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-inbox:before { content: "\e67a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-lock:before { content: "\e67b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-qrcode:before { content: "\e67c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-tags:before { content: "\e67d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-tagso:before { content: "\e67e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-cloudo:before { content: "\e67f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-cloud:before { content: "\e680"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-cloudupload:before { content: "\e681"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-clouddownload:before { content: "\e682"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-clouddownloado:before { content: "\e683"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-clouduploado:before { content: "\e684"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-enviroment:before { content: "\e685"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-enviromento:before { content: "\e686"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-eye:before { content: "\e687"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-eyeo:before { content: "\e688"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-camera:before { content: "\e689"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-camerao:before { content: "\e68a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-windows:before { content: "\e68b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-export2:before { content: "\e690"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-export:before { content: "\e691"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-circledowno:before { content: "\e693"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-circledown:before { content: "\e694"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-hdd:before { content: "\e69a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-ie:before { content: "\e69b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-delete:before { content: "\e69f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-enter:before { content: "\e6a0"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pushpino:before { content: "\e6a1"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pushpin:before { content: "\e6a2"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-heart:before { content: "\e6a3"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-hearto:before { content: "\e6a4"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-smile-circle:before { content: "\e6a7"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-smileo:before { content: "\e6a8"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-frowno:before { content: "\e6a9"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-calculator:before { content: "\e6aa"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-chrome:before { content: "\e6ac"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-github:before { content: "\e6ad"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-iconfontdesktop:before { content: "\e6b4"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-caretcircleoup:before { content: "\e6b5"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-upload:before { content: "\e6b6"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-download:before { content: "\e6b7"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-piechart:before { content: "\e6b8"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-lock1:before { content: "\e6b9"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-unlock:before { content: "\e6ba"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-windowso:before { content: "\e6bc"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-dotchart:before { content: "\e6bd"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-barchart:before { content: "\e6be"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-codesquare:before { content: "\e6bf"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-plussquare:before { content: "\e6c0"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-minussquare:before { content: "\e6c1"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-closesquare:before { content: "\e6c2"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-closesquareo:before { content: "\e6c3"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-checksquare:before { content: "\e6c4"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-checksquareo:before { content: "\e6c5"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-fastbackward:before { content: "\e6c6"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-fastforward:before { content: "\e6c7"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-upsquare:before { content: "\e6c8"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-downsquare:before { content: "\e6c9"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-leftsquare:before { content: "\e6ca"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rightsquare:before { content: "\e6cb"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rightsquareo:before { content: "\e6cc"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-leftsquareo:before { content: "\e6cd"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-down-square-o:before { content: "\e6ce"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-up-square-o:before { content: "\e6cf"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-play:before { content: "\e6d0"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-playcircleo:before { content: "\e6d1"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-tag:before { content: "\e6d2"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-tago:before { content: "\e6d3"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-addfile:before { content: "\e910"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-folder1:before { content: "\e662"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-file1:before { content: "\e664"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-switcher:before { content: "\e913"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-addfolder:before { content: "\e914"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-folderopen:before { content: "\e699"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-search1:before { content: "\e670"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-ellipsis1:before { content: "\e647"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-calendar:before { content: "\e6bb"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-filetext1:before { content: "\e698"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-copy1:before { content: "\e648"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-jpgfile1:before { content: "\e69c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pdffile1:before { content: "\e6b3"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-exclefile1:before { content: "\e6b0"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pptfile1:before { content: "\e6b1"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-unknowfile1:before { content: "\e6af"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-wordfile1:before { content: "\e6b2"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-dingding:before { content: "\e923"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-dingding-o:before { content: "\e925"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-mobile1:before { content: "\e678"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-tablet1:before { content: "\e66e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-bells:before { content: "\e64e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-disconnect:before { content: "\e64f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-database:before { content: "\e650"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-barcode:before { content: "\e652"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-hourglass:before { content: "\e653"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-key:before { content: "\e654"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-flag:before { content: "\e655"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-layout:before { content: "\e656"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-printer:before { content: "\e673"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-USB:before { content: "\e6d7"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-skin:before { content: "\e6d8"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-tool:before { content: "\e6d9"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-car:before { content: "\e6dc"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-addusergroup:before { content: "\e6dd"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-carryout:before { content: "\e6df"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-deleteuser:before { content: "\e6e0"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-deleteusergroup:before { content: "\e6e1"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-man:before { content: "\e6e2"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-isv:before { content: "\e6e3"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-gift:before { content: "\e6e4"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-idcard:before { content: "\e6e5"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-medicinebox:before { content: "\e6e6"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-redenvelopes:before { content: "\e6e7"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rest:before { content: "\e6e8"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-Safety:before { content: "\e6ea"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-wallet:before { content: "\e6eb"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-woman:before { content: "\e6ec"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-adduser:before { content: "\e6ed"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-bank:before { content: "\e6ee"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-Trophy:before { content: "\e6ef"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-loading1:before { content: "\e6ae"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-loading2:before { content: "\e64d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-like2:before { content: "\e69d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-dislike2:before { content: "\e69e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-like1:before { content: "\e64c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-dislike1:before { content: "\e64b"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-bulb1:before { content: "\e649"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-rocket1:before { content: "\e90f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-select1:before { content: "\e64a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-apple1:before { content: "\e68c"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-apple-o:before { content: "\e6d4"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-android1:before { content: "\e938"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-android:before { content: "\e68d"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-aliwangwang-o1:before { content: "\e68f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-aliwangwang:before { content: "\e68e"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pay-circle1:before { content: "\e6a5"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-pay-circle-o1:before { content: "\e6a6"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-poweroff:before { content: "\e6d5"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-trademark:before { content: "\e651"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-find:before { content: "\e6db"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-copyright:before { content: "\e6de"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-sound:before { content: "\e6e9"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-earth:before { content: "\e6f1"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-wifi:before { content: "\e6d6"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-sync:before { content: "\e6da"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-login:before { content: "\e657"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-logout:before { content: "\e65a"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-reload1:before { content: "\e616"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-message1:before { content: "\e6ab"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-shake:before { content: "\e94f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-API:before { content: "\e951"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-appstore-o:before { content: "\e695"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-appstore1:before { content: "\e696"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-scan1:before { content: "\e697"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-exception1:before { content: "\e665"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-contacts:before { content: "\e6f0"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-solution1:before { content: "\e66f"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-fork:before { content: "\e6f2"; } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.icon-edit1:before { content: "\e692"; } | 
				
			||||
 | 
					
 | 
				
			||||
| 
		 After Width: | Height: | Size: 140 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 21 KiB  | 
| 
		 After Width: | Height: | Size: 20 KiB  | 
| 
		 After Width: | Height: | Size: 21 KiB  | 
| 
		 After Width: | Height: | Size: 21 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 20 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 20 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 21 KiB  | 
| 
		 After Width: | Height: | Size: 202 KiB  | 
| 
		 After Width: | Height: | Size: 8.3 KiB  | 
| 
		 After Width: | Height: | Size: 2.9 MiB  | 
| 
		 After Width: | Height: | Size: 7.8 KiB  | 
| 
		 After Width: | Height: | Size: 1.0 MiB  | 
| 
		 After Width: | Height: | Size: 577 B  | 
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
		 After Width: | Height: | Size: 2.0 KiB  | 
| 
		 After Width: | Height: | Size: 2.4 KiB  | 
| 
		 After Width: | Height: | Size: 5.9 KiB  | 
| 
		 After Width: | Height: | Size: 19 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 917 B  | 
| 
		 After Width: | Height: | Size: 992 B  | 
@ -0,0 +1,42 @@ | 
				
			|||||
 | 
					<!DOCTYPE html> | 
				
			||||
 | 
					<html> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					<head> | 
				
			||||
 | 
					  <meta charset="UTF-8"> | 
				
			||||
 | 
					  <link rel="shortcut icon" href="/assets/images/logo.png"> | 
				
			||||
 | 
					  <link rel="stylesheet" type="text/css" href="/assets/font_sc/iconfont.css"> | 
				
			||||
 | 
					  <script type="text/javascript"> | 
				
			||||
 | 
					    window._AMapSecurityConfig = { | 
				
			||||
 | 
					      securityJsCode: 'e955cd5ddfc3a752aa27d1e1c67d182d', | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  </script> | 
				
			||||
 | 
					  <!-- <script src="https://webapi.amap.com/maps?v=2.0&key=00f9a29dedcdbd8befec3dfe0cef5003&plugin=AMap.AutoComplete,AMap.PlaceSearch"></script> --> | 
				
			||||
 | 
					  <!-- <script src="https://webapi.amap.com/loca?v=2.0.0&key=00f9a29dedcdbd8befec3dfe0cef5003"></script> --> | 
				
			||||
 | 
					</head> | 
				
			||||
 | 
					<style> | 
				
			||||
 | 
					  @font-face { | 
				
			||||
 | 
					    font-family: YouSheBiaoTiHei; | 
				
			||||
 | 
					    src: url("/assets/font_sc/YouSheBiaoTiHei-2.ttf"); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  @font-face { | 
				
			||||
 | 
					    font-family: PingFangSC-Medium; | 
				
			||||
 | 
					    src: url("/assets/font_sc/PingFang SC Medium.ttf"); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  @font-face { | 
				
			||||
 | 
					    font-family: PingFangSC-Regular; | 
				
			||||
 | 
					    src: url("/assets/font_sc/PingFang SC Regular.ttf"); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  @font-face { | 
				
			||||
 | 
					    font-family: D-DINExp-Italic; | 
				
			||||
 | 
					    src: url("/assets/font_sc/D-DINExp-Italic.otf"); | 
				
			||||
 | 
					  } | 
				
			||||
 | 
					</style> | 
				
			||||
 | 
					<body style="background: transparent"> | 
				
			||||
 | 
					  <div id='App'></div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					</body> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					</html> | 
				
			||||
@ -0,0 +1,49 @@ | 
				
			|||||
 | 
					<!DOCTYPE html> | 
				
			||||
 | 
					<html> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					<head> | 
				
			||||
 | 
					   <meta charset="UTF-8"> | 
				
			||||
 | 
					   <title></title> | 
				
			||||
 | 
					   <link rel="shortcut icon" href="/assets/images/logo.svg"> | 
				
			||||
 | 
					   <link rel="stylesheet" type="text/css" href="/assets/font_sc/iconfont.css"> | 
				
			||||
 | 
					   <script type="text/javascript"> | 
				
			||||
 | 
					      window._AMapSecurityConfig = { | 
				
			||||
 | 
					         securityJsCode: 'e955cd5ddfc3a752aa27d1e1c67d182d', | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					   </script> | 
				
			||||
 | 
					   <!-- <script src="https://webapi.amap.com/maps?v=2.0&key=00f9a29dedcdbd8befec3dfe0cef5003&plugin=AMap.AutoComplete,AMap.PlaceSearch"></script> --> | 
				
			||||
 | 
					   <!-- <script src="https://webapi.amap.com/loca?v=2.0.0&key=00f9a29dedcdbd8befec3dfe0cef5003"></script> --> | 
				
			||||
 | 
					</head> | 
				
			||||
 | 
					<style> | 
				
			||||
 | 
					   @font-face { | 
				
			||||
 | 
					      font-family: YouSheBiaoTiHei; | 
				
			||||
 | 
					      src: url("/assets/font_sc/YouSheBiaoTiHei-2.ttf"); | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					   @font-face { | 
				
			||||
 | 
					      font-family: PingFangSC-Medium; | 
				
			||||
 | 
					      src: url("/assets/font_sc/PingFang SC Medium.ttf"); | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					   @font-face { | 
				
			||||
 | 
					      font-family: PingFangSC-Regular; | 
				
			||||
 | 
					      src: url("/assets/font_sc/PingFang SC Regular.ttf"); | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					   @font-face { | 
				
			||||
 | 
					      font-family: D-DINExp-Italic; | 
				
			||||
 | 
					      src: url("/assets/font_sc/D-DINExp-Italic.otf"); | 
				
			||||
 | 
					   } | 
				
			||||
 | 
					</style> | 
				
			||||
 | 
					<body> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   <script> | 
				
			||||
 | 
					      window.less = { | 
				
			||||
 | 
					         async: false, | 
				
			||||
 | 
					         env: 'production' | 
				
			||||
 | 
					      }; | 
				
			||||
 | 
					   </script> | 
				
			||||
 | 
					   <div id='App'></div> | 
				
			||||
 | 
					   <script type="text/javascript" src="http://localhost:5901/client/build/vendor.js"></script> | 
				
			||||
 | 
					   <script type="text/javascript" src="http://localhost:5901/client/build/app.js"></script> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					</body> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					</html> | 
				
			||||
@ -0,0 +1,19 @@ | 
				
			|||||
 | 
					/** | 
				
			||||
 | 
					 * User: liuxinyi/liu.xinyi@free-sun.com.cn | 
				
			||||
 | 
					 * Date: 2016/2/22 | 
				
			||||
 | 
					 * Time: 15:29 | 
				
			||||
 | 
					 * | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const views = require('koa-view'); | 
				
			||||
 | 
					const path = require('path'); | 
				
			||||
 | 
					module.exports = { | 
				
			||||
 | 
					    entry: function (app, router, opt) { | 
				
			||||
 | 
					        app.use(views(__dirname)); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        router.get('(.*)', async function (ctx){ | 
				
			||||
 | 
					            await ctx.render(path.join(__dirname, './index')); | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					}; | 
				
			||||
@ -0,0 +1,25 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					import React, { useEffect } from 'react'; | 
				
			||||
 | 
					import Layout from './layout'; | 
				
			||||
 | 
					import Auth from './sections/auth'; | 
				
			||||
 | 
					import PublicityInfoConfig from './sections/publicityInfoConfig'; | 
				
			||||
 | 
					import QrCode from './sections/qrCode'; | 
				
			||||
 | 
					import Organization from './sections/organization'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const App = props => { | 
				
			||||
 | 
					   const { projectName } = props | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   useEffect(() => { | 
				
			||||
 | 
					      document.title = projectName; | 
				
			||||
 | 
					   }, []) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					   return ( | 
				
			||||
 | 
					      <Layout | 
				
			||||
 | 
					         title={projectName} | 
				
			||||
 | 
					         sections={[Auth, PublicityInfoConfig, QrCode, Organization,]} | 
				
			||||
 | 
					      /> | 
				
			||||
 | 
					   ) | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export default App; | 
				
			||||
@ -0,0 +1,316 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					import React, { Component } from 'react'; | 
				
			||||
 | 
					import { connect } from 'react-redux'; | 
				
			||||
 | 
					import { Spin, Upload, message, Modal, Card, Button } from 'antd'; | 
				
			||||
 | 
					import moment from 'moment'; | 
				
			||||
 | 
					import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class Uploads extends Component { | 
				
			||||
 | 
					    constructor(props) { | 
				
			||||
 | 
					        super(props); | 
				
			||||
 | 
					        this.ApiRoot = localStorage.getItem('tyApiRoot') | 
				
			||||
 | 
					        this.state = { | 
				
			||||
 | 
					            fileUploading: false, | 
				
			||||
 | 
					            fileList: [], | 
				
			||||
 | 
					            curPreviewPic: '', | 
				
			||||
 | 
					            delPicIng: false, | 
				
			||||
 | 
					            removeFilesList: [] | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    dealName = (uploaded) => { | 
				
			||||
 | 
					        let realName = uploaded.split('/')[2] | 
				
			||||
 | 
					        let x1 = realName.split('.') | 
				
			||||
 | 
					        let x2 = x1[0].split('_') | 
				
			||||
 | 
					        let showName = `${x2[0]}.${x1[1]}` | 
				
			||||
 | 
					        return showName | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // setFileList = (value) => {
 | 
				
			||||
 | 
					    //     let defaultFileList = [];
 | 
				
			||||
 | 
					    //     defaultFileList = value.map((u, index) => {
 | 
				
			||||
 | 
					    //         let fileUrl = `${this.ApiRoot}/${u.url}`;
 | 
				
			||||
 | 
					    //         return {
 | 
				
			||||
 | 
					    //             uid: -index - 1,
 | 
				
			||||
 | 
					    //             name: this.dealName(u.url),
 | 
				
			||||
 | 
					    //             status: 'done',
 | 
				
			||||
 | 
					    //             storageUrl: u.url,
 | 
				
			||||
 | 
					    //             url: fileUrl
 | 
				
			||||
 | 
					    //         };
 | 
				
			||||
 | 
					    //     });
 | 
				
			||||
 | 
					    //     onChange(defaultFileList)
 | 
				
			||||
 | 
					    //     this.setState({
 | 
				
			||||
 | 
					    //         fileList: defaultFileList
 | 
				
			||||
 | 
					    //     });
 | 
				
			||||
 | 
					    // };
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    componentDidMount() { | 
				
			||||
 | 
					        const { value } = this.props; | 
				
			||||
 | 
					        if (value) { | 
				
			||||
 | 
					            this.setState(value); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    componentWillReceiveProps(np) { | 
				
			||||
 | 
					        const { dispatch, value: thisEditData, onChange } = this.props; | 
				
			||||
 | 
					        const { value: nextEditData } = np; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        const setFileList = () => { | 
				
			||||
 | 
					            let defaultFileList = []; | 
				
			||||
 | 
					            defaultFileList = nextEditData.map((u, index) => { | 
				
			||||
 | 
					                let fileUrl = `${this.ApiRoot}/${u.storageUrl}`; | 
				
			||||
 | 
					                return { | 
				
			||||
 | 
					                    uid: -index - 1, | 
				
			||||
 | 
					                    name: this.dealName(u.storageUrl), | 
				
			||||
 | 
					                    status: 'done', | 
				
			||||
 | 
					                    storageUrl: u.storageUrl, | 
				
			||||
 | 
					                    url: fileUrl, | 
				
			||||
 | 
					                    size: u.size || -1 | 
				
			||||
 | 
					                }; | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					            this.setState({ | 
				
			||||
 | 
					                fileList: defaultFileList | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if (nextEditData && nextEditData.length) { | 
				
			||||
 | 
					            if (!thisEditData || !this.state.fileList.length) { | 
				
			||||
 | 
					                setFileList(); | 
				
			||||
 | 
					            } else if (nextEditData.length != thisEditData.length) { | 
				
			||||
 | 
					                setFileList(); | 
				
			||||
 | 
					            } else { | 
				
			||||
 | 
					                let repeat = true; | 
				
			||||
 | 
					                for (let i = 0; i < thisEditData.length; i++) { | 
				
			||||
 | 
					                    if (thisEditData[i] != nextEditData[i]) { | 
				
			||||
 | 
					                        repeat = false; | 
				
			||||
 | 
					                        break; | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (!repeat) { | 
				
			||||
 | 
					                    setFileList(); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        // else{
 | 
				
			||||
 | 
					        //     this.setState({
 | 
				
			||||
 | 
					        //         fileList:[],
 | 
				
			||||
 | 
					        //     })
 | 
				
			||||
 | 
					        // }
 | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    render() { | 
				
			||||
 | 
					        const UploadPath = { | 
				
			||||
 | 
					            project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'png', 'jpg', 'rar', 'zip'], | 
				
			||||
 | 
					            report: ['doc', 'docx', 'xls', 'xlsx', 'pdf'], | 
				
			||||
 | 
					            data: ['txt', 'xls', 'xlsx'], | 
				
			||||
 | 
					            image: ['png', 'jpg', 'svg', 'jpeg'], | 
				
			||||
 | 
					            three: ['js'], | 
				
			||||
 | 
					            video: ['mp4'] | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					        /** | 
				
			||||
 | 
					         * uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; | 
				
			||||
 | 
					         * disabled 【boolean】 上传是否可用 | 
				
			||||
 | 
					         * maxFilesNum 【number】 最大上传数量 | 
				
			||||
 | 
					         * fileTypes 【array[string]】 可允许上传的文件类型; | 
				
			||||
 | 
					         * maxFileSize 【number】 单个文件最大大小 M | 
				
			||||
 | 
					         * listType 【antd】 upload 组件的属性 | 
				
			||||
 | 
					         * onChange 【function】 文件数量变化时候回调 返回文件 | 
				
			||||
 | 
					         * value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] | 
				
			||||
 | 
					         * onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } | 
				
			||||
 | 
					         */ | 
				
			||||
 | 
					        const { | 
				
			||||
 | 
					            uploadType, | 
				
			||||
 | 
					            disabled, | 
				
			||||
 | 
					            maxFilesNum, | 
				
			||||
 | 
					            fileTypes, | 
				
			||||
 | 
					            maxFileSize, | 
				
			||||
 | 
					            listType, | 
				
			||||
 | 
					            onChange, | 
				
			||||
 | 
					            value, | 
				
			||||
 | 
					            showUploadList, | 
				
			||||
 | 
					            onStateChange | 
				
			||||
 | 
					        } = this.props; | 
				
			||||
 | 
					        const { fileList, curPreviewPic, delPicIng, removeFilesList } = this.state; | 
				
			||||
 | 
					        const that = this; | 
				
			||||
 | 
					        let uploadType_ = uploadType || 'project'; | 
				
			||||
 | 
					        let maxFilesNum_ = maxFilesNum || 1; | 
				
			||||
 | 
					        let defaultFileTypes = fileTypes || UploadPath[uploadType_]; | 
				
			||||
 | 
					        const uploadProps = { | 
				
			||||
 | 
					            name: 'checkFile_', | 
				
			||||
 | 
					            multiple: false, | 
				
			||||
 | 
					            showUploadList: showUploadList || true, | 
				
			||||
 | 
					            action: `${this.ApiRoot}/attachments/${uploadType_}`, | 
				
			||||
 | 
					            listType: listType || 'text', | 
				
			||||
 | 
					            disabled: disabled, | 
				
			||||
 | 
					            beforeUpload: (file) => { | 
				
			||||
 | 
					                if (fileList.length >= maxFilesNum_) { | 
				
			||||
 | 
					                    message.warning(`最多选择${maxFilesNum_}个文件上传`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (file.name.length > 60) { | 
				
			||||
 | 
					                    message.warning(`文件名过长(大于60字符),请修改后上传`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                const extNames = file.name.split('.'); | 
				
			||||
 | 
					                var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/; | 
				
			||||
 | 
					                if (!reg.exec(file.name)) { | 
				
			||||
 | 
					                    message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                let isDAE = false; | 
				
			||||
 | 
					                if (extNames.length > 0) { | 
				
			||||
 | 
					                    let fileType = extNames[extNames.length - 1].toLowerCase(); | 
				
			||||
 | 
					                    isDAE = defaultFileTypes.some((f) => f == fileType); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (!isDAE) { | 
				
			||||
 | 
					                    message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); | 
				
			||||
 | 
					                if (!isLt) { | 
				
			||||
 | 
					                    message.error(`文件必须小于${maxFileSize || 3}MB!`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                this.setState({ | 
				
			||||
 | 
					                    fileUploading: true | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					                if (onStateChange) { | 
				
			||||
 | 
					                    onStateChange({ uploading: true }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            onChange(info) { | 
				
			||||
 | 
					                const status = info.file.status; | 
				
			||||
 | 
					                if (status === 'uploading') { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        fileList: info.fileList | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (status === 'done') { | 
				
			||||
 | 
					                    let { uploaded, url } = info.file.response; | 
				
			||||
 | 
					                    let size = info.file.size; | 
				
			||||
 | 
					                    let nextFileList = fileList; | 
				
			||||
 | 
					                    nextFileList[nextFileList.length - 1] = { | 
				
			||||
 | 
					                        uid: -moment().unix(), | 
				
			||||
 | 
					                        name: that.dealName(uploaded), | 
				
			||||
 | 
					                        status: 'done', | 
				
			||||
 | 
					                        storageUrl: uploaded, | 
				
			||||
 | 
					                        url: url, | 
				
			||||
 | 
					                        size: size | 
				
			||||
 | 
					                    }; | 
				
			||||
 | 
					                    onChange(nextFileList); | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        fileUploading: false, | 
				
			||||
 | 
					                        fileList: nextFileList | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                    if (onStateChange) { | 
				
			||||
 | 
					                        onStateChange({ uploading: false }); | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } else if (status === 'error') { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        fileUploading: false | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                    message.error(`${info.file.name} 上传失败,请重试`); | 
				
			||||
 | 
					                    if (onStateChange) { | 
				
			||||
 | 
					                        onStateChange({ uploading: false }); | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            onRemove(file) { | 
				
			||||
 | 
					                let nextFileList = []; | 
				
			||||
 | 
					                fileList.map((f, i) => { | 
				
			||||
 | 
					                    if (f.uid != file.uid) { | 
				
			||||
 | 
					                        nextFileList.push(f); | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					                let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); | 
				
			||||
 | 
					                if (curPreviewPic == file.url) { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        curPreviewPic: '' | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                onChange(nextFileList); | 
				
			||||
 | 
					                that.setState({ | 
				
			||||
 | 
					                    fileList: nextFileList, | 
				
			||||
 | 
					                    removeFilesList: nextRemoveFiles | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            onPreview(file) { | 
				
			||||
 | 
					                let filePostfix = file.url.split('.').pop(); | 
				
			||||
 | 
					                filePostfix = filePostfix.toLowerCase(); | 
				
			||||
 | 
					                if (UploadPath.image.some((img) => img == filePostfix)) { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        curPreviewPic: file.url | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } else { | 
				
			||||
 | 
					                    message.warn('仅支持图片预览'); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        let fileList_ = fileList | 
				
			||||
 | 
					        // .map(f => {
 | 
				
			||||
 | 
					        //     if (f.storageUrl) {
 | 
				
			||||
 | 
					        //         let realName = f.storageUrl.split('/').pop()
 | 
				
			||||
 | 
					        //         if (f.name != realName) {
 | 
				
			||||
 | 
					        //             f.name = realName
 | 
				
			||||
 | 
					        //         }
 | 
				
			||||
 | 
					        //     }
 | 
				
			||||
 | 
					        //     return f
 | 
				
			||||
 | 
					        // })
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        return ( | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <Spin spinning={delPicIng}> | 
				
			||||
 | 
					                    <Upload {...uploadProps} fileList={fileList_}> | 
				
			||||
 | 
					                        { | 
				
			||||
 | 
					                            disabled ? ( | 
				
			||||
 | 
					                                '' | 
				
			||||
 | 
					                            ) : | 
				
			||||
 | 
					                                listType == 'picture-card' ? | 
				
			||||
 | 
					                                    ( | 
				
			||||
 | 
					                                        fileList.length >= maxFilesNum_ ? null : ( | 
				
			||||
 | 
					                                            <div style={{}}> | 
				
			||||
 | 
					                                                <PlusOutlined /> | 
				
			||||
 | 
					                                                <div>上传图片</div> | 
				
			||||
 | 
					                                            </div> | 
				
			||||
 | 
					                                        ) | 
				
			||||
 | 
					                                    ) : ( | 
				
			||||
 | 
					                                        <Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}>  文件上传 </Button> | 
				
			||||
 | 
					                                    ) | 
				
			||||
 | 
					                        } | 
				
			||||
 | 
					                    </Upload> | 
				
			||||
 | 
					                    { | 
				
			||||
 | 
					                        curPreviewPic ? ( | 
				
			||||
 | 
					                            <Card | 
				
			||||
 | 
					                                bodyStyle={{ | 
				
			||||
 | 
					                                    padding: 8 | 
				
			||||
 | 
					                                }} | 
				
			||||
 | 
					                            > | 
				
			||||
 | 
					                                <div style={{ marginBottom: 8 }} > | 
				
			||||
 | 
					                                    <span>文件预览</span> | 
				
			||||
 | 
					                                    <span | 
				
			||||
 | 
					                                        style={{ float: 'right' }} | 
				
			||||
 | 
					                                        onClick={() => { this.setState({ curPreviewPic: '' }); }} | 
				
			||||
 | 
					                                    > | 
				
			||||
 | 
					                                        <CloseOutlined style={{ fontSize: 20 }} /> | 
				
			||||
 | 
					                                    </span> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                                <img style={{ width: '100%' }} src={curPreviewPic}></img> | 
				
			||||
 | 
					                            </Card> | 
				
			||||
 | 
					                        ) : '' | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                </Spin> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        ); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					function mapStateToProps(state) { | 
				
			||||
 | 
					    const { auth } = state | 
				
			||||
 | 
					    return { | 
				
			||||
 | 
					        user: auth.user | 
				
			||||
 | 
					    }; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export default connect(mapStateToProps)(Uploads); | 
				
			||||
@ -0,0 +1,389 @@ | 
				
			|||||
 | 
					'use strict'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					import React, { Component } from 'react'; | 
				
			||||
 | 
					import { connect } from 'react-redux'; | 
				
			||||
 | 
					import { Spin, Upload, message, Modal, Card, Button } from 'antd'; | 
				
			||||
 | 
					import moment from 'moment'; | 
				
			||||
 | 
					import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class Uploads extends Component { | 
				
			||||
 | 
					    constructor(props) { | 
				
			||||
 | 
					        super(props); | 
				
			||||
 | 
					        this.ApiRoot = localStorage.getItem('tyApiRoot') | 
				
			||||
 | 
					        this.qnDomain = localStorage.getItem('qnDomain'); | 
				
			||||
 | 
					        this.aliAdmin = localStorage.getItem('aliAdmin'); | 
				
			||||
 | 
					        this.state = { | 
				
			||||
 | 
					            fileUploading: false, | 
				
			||||
 | 
					            fileList: [], | 
				
			||||
 | 
					            curPreviewPic: '', | 
				
			||||
 | 
					            curPreviewVideo: '', | 
				
			||||
 | 
					            delPicIng: false, | 
				
			||||
 | 
					            removeFilesList: [] | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    dealName = (uploaded) => { | 
				
			||||
 | 
					        let realName = uploaded.split('/')[2] | 
				
			||||
 | 
					        // let x1 = realName.split('.')
 | 
				
			||||
 | 
					        // let postfix = x1.pop()
 | 
				
			||||
 | 
					        // let allName = x1.join('.')
 | 
				
			||||
 | 
					        // let x2 = allName.split('_')
 | 
				
			||||
 | 
					        // let showName = `${x2[0]}.${postfix}`
 | 
				
			||||
 | 
					        return realName | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // setFileList = (value) => {
 | 
				
			||||
 | 
					    //     let defaultFileList = [];
 | 
				
			||||
 | 
					    //     defaultFileList = value.map((u, index) => {
 | 
				
			||||
 | 
					    //         let fileUrl = `${this.ApiRoot}/${u.url}`;
 | 
				
			||||
 | 
					    //         return {
 | 
				
			||||
 | 
					    //             uid: -index - 1,
 | 
				
			||||
 | 
					    //             name: this.dealName(u.url),
 | 
				
			||||
 | 
					    //             status: 'done',
 | 
				
			||||
 | 
					    //             storageUrl: u.url,
 | 
				
			||||
 | 
					    //             url: fileUrl
 | 
				
			||||
 | 
					    //         };
 | 
				
			||||
 | 
					    //     });
 | 
				
			||||
 | 
					    //     onChange(defaultFileList)
 | 
				
			||||
 | 
					    //     this.setState({
 | 
				
			||||
 | 
					    //         fileList: defaultFileList
 | 
				
			||||
 | 
					    //     });
 | 
				
			||||
 | 
					    // };
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    setFileList = (nextEditData, isQiniu, isAli) => { | 
				
			||||
 | 
					        let defaultFileList = []; | 
				
			||||
 | 
					        defaultFileList = nextEditData.map((u, index) => { | 
				
			||||
 | 
					            let fileUrl = | 
				
			||||
 | 
					                isQiniu ? `/_file-server/${u.storageUrl}` | 
				
			||||
 | 
					                    : isAli ? `/_file-ali-server/${u.storageUrl}` | 
				
			||||
 | 
					                        : `${this.ApiRoot}/${u.storageUrl}`; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            return { | 
				
			||||
 | 
					                uid: -index - 1, | 
				
			||||
 | 
					                name: this.dealName(u.storageUrl), | 
				
			||||
 | 
					                status: 'done', | 
				
			||||
 | 
					                storageUrl: u.storageUrl, | 
				
			||||
 | 
					                url: fileUrl, | 
				
			||||
 | 
					                size: u.size || -1 | 
				
			||||
 | 
					            }; | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					        this.setState({ | 
				
			||||
 | 
					            fileList: defaultFileList | 
				
			||||
 | 
					        }); | 
				
			||||
 | 
					    }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    componentDidMount() { | 
				
			||||
 | 
					        const { value, defaultValue, isQiniu, isAli } = this.props; | 
				
			||||
 | 
					        if (defaultValue) { | 
				
			||||
 | 
					            this.setFileList(defaultValue, isQiniu, isAli) | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    UNSAFE_componentWillReceiveProps(np) { | 
				
			||||
 | 
					        const { dispatch, value: thisEditData, onChange } = this.props; | 
				
			||||
 | 
					        const { value: nextEditData, isQiniu, isAli } = np; | 
				
			||||
 | 
					        // this.setFileList(nextEditData, isQiniu)
 | 
				
			||||
 | 
					        // const setFileList = () => {
 | 
				
			||||
 | 
					        //     let defaultFileList = [];
 | 
				
			||||
 | 
					        //     defaultFileList = nextEditData.map((u, index) => {
 | 
				
			||||
 | 
					        //         let fileUrl = isQiniu ? `/_file-server/${u.storageUrl}` : `${this.ApiRoot}/${u.storageUrl}`;
 | 
				
			||||
 | 
					        //         return {
 | 
				
			||||
 | 
					        //             uid: -index - 1,
 | 
				
			||||
 | 
					        //             name: this.dealName(u.storageUrl),
 | 
				
			||||
 | 
					        //             status: 'done',
 | 
				
			||||
 | 
					        //             storageUrl: u.storageUrl,
 | 
				
			||||
 | 
					        //             url: fileUrl,
 | 
				
			||||
 | 
					        //             size: u.size || -1
 | 
				
			||||
 | 
					        //         };
 | 
				
			||||
 | 
					        //     });
 | 
				
			||||
 | 
					        //     this.setState({
 | 
				
			||||
 | 
					        //         fileList: defaultFileList
 | 
				
			||||
 | 
					        //     });
 | 
				
			||||
 | 
					        // };
 | 
				
			||||
 | 
					        if (nextEditData && nextEditData.length) { | 
				
			||||
 | 
					            if (!thisEditData || !this.state.fileList.length) { | 
				
			||||
 | 
					                this.setFileList(nextEditData, isQiniu, isAli); | 
				
			||||
 | 
					            } else if (nextEditData.length != thisEditData.length) { | 
				
			||||
 | 
					                this.setFileList(nextEditData, isQiniu, isAli); | 
				
			||||
 | 
					            } else { | 
				
			||||
 | 
					                let repeat = true; | 
				
			||||
 | 
					                for (let i = 0; i < thisEditData.length; i++) { | 
				
			||||
 | 
					                    if (thisEditData[i] != nextEditData[i]) { | 
				
			||||
 | 
					                        repeat = false; | 
				
			||||
 | 
					                        break; | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (!repeat) { | 
				
			||||
 | 
					                    this.setFileList(nextEditData, isQiniu, isAli); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        // else{
 | 
				
			||||
 | 
					        //     this.setState({
 | 
				
			||||
 | 
					        //         fileList:[],
 | 
				
			||||
 | 
					        //     })
 | 
				
			||||
 | 
					        // }
 | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    render() { | 
				
			||||
 | 
					        const UploadPath = { | 
				
			||||
 | 
					            project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf', 'pptx', 'png', 'jpg', 'svg', 'jpeg', 'rar', 'zip', 'jpeg', 'mp4'], | 
				
			||||
 | 
					            report: ['doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf'], | 
				
			||||
 | 
					            data: ['txt', 'xls', 'xlsx', 'csv'], | 
				
			||||
 | 
					            image: ['png', 'jpg', 'svg', 'jpeg'], | 
				
			||||
 | 
					            three: ['js'], | 
				
			||||
 | 
					            video: ['mp4'] | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					        /** | 
				
			||||
 | 
					         * uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; | 
				
			||||
 | 
					         * disabled 【boolean】 上传是否可用 | 
				
			||||
 | 
					         * maxFilesNum 【number】 最大上传数量 | 
				
			||||
 | 
					         * fileTypes 【array[string]】 可允许上传的文件类型; | 
				
			||||
 | 
					         * maxFileSize 【number】 单个文件最大大小 M | 
				
			||||
 | 
					         * listType 【antd】 upload 组件的属性 | 
				
			||||
 | 
					         * onChange 【function】 文件数量变化时候回调 返回文件 | 
				
			||||
 | 
					         * value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] | 
				
			||||
 | 
					         * onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } | 
				
			||||
 | 
					         */ | 
				
			||||
 | 
					        const { | 
				
			||||
 | 
					            uploadType, | 
				
			||||
 | 
					            disabled, | 
				
			||||
 | 
					            maxFilesNum, | 
				
			||||
 | 
					            fileTypes, | 
				
			||||
 | 
					            maxFileSize, | 
				
			||||
 | 
					            listType, | 
				
			||||
 | 
					            onChange = () => { }, | 
				
			||||
 | 
					            value, | 
				
			||||
 | 
					            showUploadList, | 
				
			||||
 | 
					            onStateChange, | 
				
			||||
 | 
					            isQiniu, | 
				
			||||
 | 
					            isAli, | 
				
			||||
 | 
					        } = this.props; | 
				
			||||
 | 
					        const { fileList, curPreviewPic, curPreviewVideo, delPicIng, removeFilesList } = this.state; | 
				
			||||
 | 
					        const that = this; | 
				
			||||
 | 
					        let uploadType_ = uploadType || 'project'; | 
				
			||||
 | 
					        let maxFilesNum_ = maxFilesNum || 1; | 
				
			||||
 | 
					        let defaultFileTypes = fileTypes || UploadPath[uploadType_]; | 
				
			||||
 | 
					        // debugger
 | 
				
			||||
 | 
					        const uploadProps = { | 
				
			||||
 | 
					            name: 'checkFile_', | 
				
			||||
 | 
					            multiple: false, | 
				
			||||
 | 
					            showUploadList: showUploadList || true, | 
				
			||||
 | 
					            action: | 
				
			||||
 | 
					                isQiniu ? `/_upload/attachments/${uploadType_}` | 
				
			||||
 | 
					                    : isAli ? `/_upload/attachments/ali/${uploadType_}` | 
				
			||||
 | 
					                        : `${this.ApiRoot}/attachments/${uploadType_}`, | 
				
			||||
 | 
					            listType: listType || 'text', | 
				
			||||
 | 
					            disabled: disabled, | 
				
			||||
 | 
					            beforeUpload: (file) => { | 
				
			||||
 | 
					                if (fileList.length >= maxFilesNum_) { | 
				
			||||
 | 
					                    message.warning(`最多选择${maxFilesNum_}个文件上传`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (file.name.length > 60) { | 
				
			||||
 | 
					                    message.warning(`文件名过长(大于60字符),请修改后上传`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                const extNames = file.name.split('.'); | 
				
			||||
 | 
					                // var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/;
 | 
				
			||||
 | 
					                // if (!reg.exec(file.name)) {
 | 
				
			||||
 | 
					                //     message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`);
 | 
				
			||||
 | 
					                //     return false;
 | 
				
			||||
 | 
					                // }
 | 
				
			||||
 | 
					                let isDAE = false; | 
				
			||||
 | 
					                if (extNames.length > 0) { | 
				
			||||
 | 
					                    let fileType = extNames[extNames.length - 1].toLowerCase(); | 
				
			||||
 | 
					                    isDAE = defaultFileTypes.some((f) => f == fileType); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (!isDAE) { | 
				
			||||
 | 
					                    message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); | 
				
			||||
 | 
					                if (!isLt) { | 
				
			||||
 | 
					                    message.error(`文件必须小于${maxFileSize || 3}MB!`); | 
				
			||||
 | 
					                    return false; | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                this.setState({ | 
				
			||||
 | 
					                    fileUploading: true | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					                if (onStateChange) { | 
				
			||||
 | 
					                    onStateChange({ uploading: true }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            onChange(info) { | 
				
			||||
 | 
					                const status = info.file.status; | 
				
			||||
 | 
					                if (status === 'uploading') { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        fileList: info.fileList | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (status === 'done') { | 
				
			||||
 | 
					                    let { uploaded, url } = info.file.response; | 
				
			||||
 | 
					                    let size = info.file.size; | 
				
			||||
 | 
					                    let nextFileList = fileList; | 
				
			||||
 | 
					                    nextFileList[nextFileList.length - 1] = { | 
				
			||||
 | 
					                        uid: -moment().unix(), | 
				
			||||
 | 
					                        name: that.dealName(uploaded), | 
				
			||||
 | 
					                        status: 'done', | 
				
			||||
 | 
					                        storageUrl: uploaded, | 
				
			||||
 | 
					                        url: | 
				
			||||
 | 
					                            isQiniu ? '/_file-server/' + uploaded : | 
				
			||||
 | 
					                                isAli ? `/_file-ali-server/${uploaded}` : | 
				
			||||
 | 
					                                    url, | 
				
			||||
 | 
					                        size: size | 
				
			||||
 | 
					                    }; | 
				
			||||
 | 
					                    onChange(nextFileList); | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        fileUploading: false, | 
				
			||||
 | 
					                        fileList: nextFileList | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                    if (onStateChange) { | 
				
			||||
 | 
					                        onStateChange({ uploading: false }); | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } else if (status === 'error') { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        fileUploading: false | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                    message.error(`${info.file.name} 上传失败,请重试`); | 
				
			||||
 | 
					                    if (onStateChange) { | 
				
			||||
 | 
					                        onStateChange({ uploading: false }); | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            onRemove(file) { | 
				
			||||
 | 
					                let nextFileList = []; | 
				
			||||
 | 
					                fileList.map((f, i) => { | 
				
			||||
 | 
					                    if (f.uid != file.uid) { | 
				
			||||
 | 
					                        nextFileList.push(f); | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					                let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); | 
				
			||||
 | 
					                if (curPreviewPic == file.url) { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        curPreviewPic: '' | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                if (curPreviewVideo == file.url) { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        curPreviewVideo: '' | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					                onChange(nextFileList); | 
				
			||||
 | 
					                that.setState({ | 
				
			||||
 | 
					                    fileList: nextFileList, | 
				
			||||
 | 
					                    removeFilesList: nextRemoveFiles | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					            }, | 
				
			||||
 | 
					            onPreview(file) { | 
				
			||||
 | 
					                let filePostfix = file.url.split('.').pop(); | 
				
			||||
 | 
					                filePostfix = filePostfix.toLowerCase(); | 
				
			||||
 | 
					                if (UploadPath.image.some((img) => img == filePostfix)) { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        curPreviewPic: file.url | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } else if (UploadPath.video.some((img) => img == filePostfix)) { | 
				
			||||
 | 
					                    that.setState({ | 
				
			||||
 | 
					                        curPreviewVideo: file.url | 
				
			||||
 | 
					                    }); | 
				
			||||
 | 
					                } else { | 
				
			||||
 | 
					                    //message.warn('仅支持图片预览');
 | 
				
			||||
 | 
					                    preview(file.storageUrl) | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        const preview = (url) => { | 
				
			||||
 | 
					            let link = isQiniu ? encodeURI(`${this.qnDomain}/${url}`) : | 
				
			||||
 | 
					                isAli ? encodeURI(`${this.aliAdmin}/${url}`) : '' | 
				
			||||
 | 
					            if (link) | 
				
			||||
 | 
					                if (url.indexOf("pdf") !== -1 || url.indexOf("csv") !== -1) { | 
				
			||||
 | 
					                    window.open(link) | 
				
			||||
 | 
					                } else { | 
				
			||||
 | 
					                    window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`) | 
				
			||||
 | 
					                } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        let fileList_ = fileList | 
				
			||||
 | 
					        // .map(f => {
 | 
				
			||||
 | 
					        //     if (f.storageUrl) {
 | 
				
			||||
 | 
					        //         let realName = f.storageUrl.split('/').pop()
 | 
				
			||||
 | 
					        //         if (f.name != realName) {
 | 
				
			||||
 | 
					        //             f.name = realName
 | 
				
			||||
 | 
					        //         }
 | 
				
			||||
 | 
					        //     }
 | 
				
			||||
 | 
					        //     return f
 | 
				
			||||
 | 
					        // })
 | 
				
			||||
 | 
					        //下载文件
 | 
				
			||||
 | 
					        const handleDownload = (file) => { | 
				
			||||
 | 
					            saveAs(file) | 
				
			||||
 | 
					        }; | 
				
			||||
 | 
					        const saveAs = (file) => { | 
				
			||||
 | 
					            const link = document.createElement('a'); | 
				
			||||
 | 
					            link.href = file.url; | 
				
			||||
 | 
					            link.download = file.name; | 
				
			||||
 | 
					            link.style.display = 'none'; | 
				
			||||
 | 
					            link.click(); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        //自定义下载
 | 
				
			||||
 | 
					        return ( | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <Spin spinning={delPicIng}> | 
				
			||||
 | 
					                    <Upload {...uploadProps} fileList={fileList_} showUploadList={{ showDownloadIcon: true }} onDownload={handleDownload}> | 
				
			||||
 | 
					                        { | 
				
			||||
 | 
					                            disabled ? ( | 
				
			||||
 | 
					                                '' | 
				
			||||
 | 
					                            ) : | 
				
			||||
 | 
					                                listType == 'picture-card' ? | 
				
			||||
 | 
					                                    ( | 
				
			||||
 | 
					                                        fileList.length >= maxFilesNum_ ? null : ( | 
				
			||||
 | 
					                                            <div style={{}}> | 
				
			||||
 | 
					                                                <PlusOutlined /> | 
				
			||||
 | 
					                                                <div>添加附件</div> | 
				
			||||
 | 
					                                            </div> | 
				
			||||
 | 
					                                        ) | 
				
			||||
 | 
					                                    ) : ( | 
				
			||||
 | 
					                                        <Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}>  文件上传 </Button> | 
				
			||||
 | 
					                                    ) | 
				
			||||
 | 
					                        } | 
				
			||||
 | 
					                    </Upload> | 
				
			||||
 | 
					                    { | 
				
			||||
 | 
					                        curPreviewPic ? ( | 
				
			||||
 | 
					                            <Card bodyStyle={{ padding: 8 }}> | 
				
			||||
 | 
					                                <div style={{ marginBottom: 8 }} > | 
				
			||||
 | 
					                                    <span>图片预览</span> | 
				
			||||
 | 
					                                    <span style={{ float: 'right' }} onClick={() => { this.setState({ curPreviewPic: '' }) }}> | 
				
			||||
 | 
					                                        <CloseOutlined style={{ fontSize: 20 }} /> | 
				
			||||
 | 
					                                    </span> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                                <img style={{ width: '100%' }} src={curPreviewPic} /> | 
				
			||||
 | 
					                            </Card> | 
				
			||||
 | 
					                        ) : '' | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                    { | 
				
			||||
 | 
					                        curPreviewVideo ? (<Card bodyStyle={{ padding: 8 }}> | 
				
			||||
 | 
					                            <div style={{ marginBottom: 8 }} > | 
				
			||||
 | 
					                                <span>视频预览</span> | 
				
			||||
 | 
					                                <span style={{ float: 'right' }} onClick={() => { this.setState({ curPreviewVideo: '' }) }}> | 
				
			||||
 | 
					                                    <CloseOutlined style={{ fontSize: 20 }} /> | 
				
			||||
 | 
					                                </span> | 
				
			||||
 | 
					                            </div> | 
				
			||||
 | 
					                            <video controls style={{ width: '100%' }}> | 
				
			||||
 | 
					                                <source src={curPreviewVideo} type="video/mp4"></source> | 
				
			||||
 | 
					                            </video> | 
				
			||||
 | 
					                        </Card>) : '' | 
				
			||||
 | 
					                    } | 
				
			||||
 | 
					                </Spin> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        ); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					function mapStateToProps(state) { | 
				
			||||
 | 
					    const { auth } = state | 
				
			||||
 | 
					    return { | 
				
			||||
 | 
					        user: auth.user | 
				
			||||
 | 
					    }; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export default connect(mapStateToProps)(Uploads); | 
				
			||||
@ -0,0 +1,683 @@ | 
				
			|||||
 | 
					/** | 
				
			||||
 | 
					 * Created by Xumeng 2020/04/22. | 
				
			||||
 | 
					 */ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					import React, { useState, useEffect } from 'react'; | 
				
			||||
 | 
					import PropTypes from 'prop-types'; | 
				
			||||
 | 
					import { | 
				
			||||
 | 
					  Row, Col, Space, Button, message, notification, Form, Input, Tooltip, Menu, Dropdown, | 
				
			||||
 | 
					} from 'antd'; | 
				
			||||
 | 
					import moment from 'moment'; | 
				
			||||
 | 
					import XLSX from 'xlsx'; | 
				
			||||
 | 
					import { fromJS } from 'immutable'; | 
				
			||||
 | 
					import { Request } from '@peace/utils'; | 
				
			||||
 | 
					import FileSaver from 'file-saver'; | 
				
			||||
 | 
					import './index.less'; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// 通用前端导入导出组件  使用方法查看底部propTypes
 | 
				
			||||
 | 
					function ExportAndImport(props) { | 
				
			||||
 | 
					  const [form] = Form.useForm(); | 
				
			||||
 | 
					  const [exportLoading, setExportLoading] = useState(false); | 
				
			||||
 | 
					  const [importLoading, setImportLoading] = useState(false); | 
				
			||||
 | 
					  const { | 
				
			||||
 | 
					    importDataCallback, onImportSucess, handelData, importMethod = 'post', | 
				
			||||
 | 
					  } = props; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  useEffect(() => () => { | 
				
			||||
 | 
					    // 只有unmount 时调用
 | 
				
			||||
 | 
					    notification.close('import-notification'); | 
				
			||||
 | 
					  }); | 
				
			||||
 | 
					  const importExcel = (file, type) => { | 
				
			||||
 | 
					    setImportLoading(true); | 
				
			||||
 | 
					    // 获取上传的文件对象
 | 
				
			||||
 | 
					    const { files } = file.target; | 
				
			||||
 | 
					    // 判断xls、xlsx格式
 | 
				
			||||
 | 
					    if (files[0].type.indexOf('sheet') > -1 || files[0].type.indexOf('ms-excel') > -1) { | 
				
			||||
 | 
					      // 通过FileReader对象读取文件
 | 
				
			||||
 | 
					      const fileReader = new FileReader(); | 
				
			||||
 | 
					      fileReader.onload = (event) => { | 
				
			||||
 | 
					        try { | 
				
			||||
 | 
					          const { importRequest = true, importUrl, importQuery } = props; | 
				
			||||
 | 
					          if (importRequest && !importUrl) { | 
				
			||||
 | 
					            message.error('获取导入接口失败!'); | 
				
			||||
 | 
					            form.resetFields(); | 
				
			||||
 | 
					            return; | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					          const { result } = event.target; | 
				
			||||
 | 
					          // 以二进制流方式读取得到整份excel表格对象
 | 
				
			||||
 | 
					          const workbook = XLSX.read(result, { type: 'binary', cellDates: true }); | 
				
			||||
 | 
					          let data = []; // 存储获取到的数据
 | 
				
			||||
 | 
					          // 遍历每张工作表进行读取(这里默认只读取第一张表)
 | 
				
			||||
 | 
					          for (const sheet in workbook.Sheets) { | 
				
			||||
 | 
					            if (workbook.Sheets.hasOwnProperty(sheet)) { | 
				
			||||
 | 
					              // 利用 sheet_to_json 方法将 excel 转成 json 数据
 | 
				
			||||
 | 
					              data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet])); | 
				
			||||
 | 
					              break; // 如果只取第一张表,就取消注释这行
 | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					          if (data.length > 10000) { | 
				
			||||
 | 
					            message.error('一次最多导入10000条数据,请分批导入!'); | 
				
			||||
 | 
					            form.resetFields(); | 
				
			||||
 | 
					            setImportLoading(false); | 
				
			||||
 | 
					            return; | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					          if (importRequest) { | 
				
			||||
 | 
					            message.success('获取文件数据成功,开始处理导入...'); | 
				
			||||
 | 
					            const importData = handelData ? handelData(data) : data; | 
				
			||||
 | 
					            Request[importMethod](importUrl, { data: importData }, importQuery || {}).then((res) => { | 
				
			||||
 | 
					              message.success('导入数据成功'); | 
				
			||||
 | 
					              form.resetFields(); | 
				
			||||
 | 
					              notification.close('import-notification'); | 
				
			||||
 | 
					              setImportLoading(false); | 
				
			||||
 | 
					              onImportSucess && onImportSucess(); | 
				
			||||
 | 
					            }, (err) => { | 
				
			||||
 | 
					              if (err.status === 500) { | 
				
			||||
 | 
					                message.error('数据导入出错,导入失败'); | 
				
			||||
 | 
					              } else if (err.status === 400) { | 
				
			||||
 | 
					                message.error(err.body.message || '数据验证出错,请检查数据格式是否正确'); | 
				
			||||
 | 
					              } else { | 
				
			||||
 | 
					                message.error('导入失败'); | 
				
			||||
 | 
					              } | 
				
			||||
 | 
					              form.resetFields(); | 
				
			||||
 | 
					              setImportLoading(false); | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					          } else { | 
				
			||||
 | 
					            form.resetFields(); | 
				
			||||
 | 
					            setImportLoading(false); | 
				
			||||
 | 
					            importDataCallback && importDataCallback(data, type); | 
				
			||||
 | 
					            notification.close('import-notification'); | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        } catch (e) { | 
				
			||||
 | 
					          console.log(e); | 
				
			||||
 | 
					          // 这里可以抛出文件类型错误不正确的相关提示
 | 
				
			||||
 | 
					          message.error('文件格式不正确!'); | 
				
			||||
 | 
					          setImportLoading(false); | 
				
			||||
 | 
					          form.resetFields(); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      }; | 
				
			||||
 | 
					      // fileReader.onloadend = (event) => {
 | 
				
			||||
 | 
					      //     console.log(event)
 | 
				
			||||
 | 
					      // }
 | 
				
			||||
 | 
					      // 以二进制方式打开文件
 | 
				
			||||
 | 
					      fileReader.readAsBinaryString(files[0]); | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					      message.error('文件格式不正确!'); | 
				
			||||
 | 
					      form.resetFields(); | 
				
			||||
 | 
					      setImportLoading(false); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const loop = (data, keypath, values) => { // deal with array
 | 
				
			||||
 | 
					    const dkey = keypath.slice(0, 1)[0]; | 
				
			||||
 | 
					    console.log(dkey); | 
				
			||||
 | 
					    if (dkey) { | 
				
			||||
 | 
					      const dvalue = data[dkey]; | 
				
			||||
 | 
					      const otherKeypath = keypath.slice(1); | 
				
			||||
 | 
					      if (Array.isArray(dvalue)) { | 
				
			||||
 | 
					        if (otherKeypath.length) { | 
				
			||||
 | 
					          const immutableData = fromJS(data); | 
				
			||||
 | 
					          for (let index = 0; index < dvalue.length; index++) { | 
				
			||||
 | 
					            const tmp = immutableData.getIn([dkey, index]).toJS(); | 
				
			||||
 | 
					            loop(tmp, otherKeypath, values); | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      } else { | 
				
			||||
 | 
					        values.push(dvalue); | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return values; | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  const getColumnData = (opts) => { | 
				
			||||
 | 
					    const { | 
				
			||||
 | 
					      data, keypath, render, spliter, rawdata, | 
				
			||||
 | 
					    } = opts; | 
				
			||||
 | 
					    let v = null; | 
				
			||||
 | 
					    const outer = data[keypath[0]]; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    if (Array.isArray(outer)) { | 
				
			||||
 | 
					      const values = loop(data, keypath, []); | 
				
			||||
 | 
					      v = rawdata ? values : values.join(spliter || ','); | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					      v = fromJS(data).getIn(keypath); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    // 处理render
 | 
				
			||||
 | 
					    if (render && typeof render === 'function') { | 
				
			||||
 | 
					      v = render(outer, data); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return v; | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  const getDataSource = (attrs, filterData) => { | 
				
			||||
 | 
					    // let token = JSON.parse(sessionStorage.getItem('user')).token;
 | 
				
			||||
 | 
					    const dataSource = filterData.map((item) => { | 
				
			||||
 | 
					      const record = {}; | 
				
			||||
 | 
					      attrs.forEach((attr) => { | 
				
			||||
 | 
					        const { | 
				
			||||
 | 
					          key, dataIndex, render, child, | 
				
			||||
 | 
					        } = attr; | 
				
			||||
 | 
					        if (child) { | 
				
			||||
 | 
					          record[key] = getDataSource(child, item[key]); | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					          const v = getColumnData({ | 
				
			||||
 | 
					            data: item, | 
				
			||||
 | 
					            keypath: dataIndex || [key], | 
				
			||||
 | 
					            render: render || null, | 
				
			||||
 | 
					          }); | 
				
			||||
 | 
					          record[key] = v; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					      return record; | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					    return dataSource; | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  // 暂时只处理两层
 | 
				
			||||
 | 
					  const getFlatData = (attrs, filterData, dataToAoa, deep = 0) => { | 
				
			||||
 | 
					    filterData.map((item) => { | 
				
			||||
 | 
					      let cur = dataToAoa[deep]; | 
				
			||||
 | 
					      if (!cur) { | 
				
			||||
 | 
					        cur = dataToAoa[deep] = []; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					      attrs.map((attr, index) => { | 
				
			||||
 | 
					        const { key, child } = attr; | 
				
			||||
 | 
					        if (child) { | 
				
			||||
 | 
					          if (Array.isArray(item[key])) { | 
				
			||||
 | 
					            // getFlatData(child,item[key],dataToAoa,deep)
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            item[key].map((s, i) => { | 
				
			||||
 | 
					              if (i == 0) { | 
				
			||||
 | 
					                child.map((c) => { | 
				
			||||
 | 
					                  cur.push(s[c.key]); | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					              } else { | 
				
			||||
 | 
					                deep++; | 
				
			||||
 | 
					                const childCur = dataToAoa[deep] = []; | 
				
			||||
 | 
					                pushNull(childCur, index); | 
				
			||||
 | 
					                child.map((c) => { | 
				
			||||
 | 
					                  childCur.push(s[c.key]); | 
				
			||||
 | 
					                }); | 
				
			||||
 | 
					              } | 
				
			||||
 | 
					            }); | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					          cur.push(item[key]); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					      deep++; | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const getHeader = (headers, excelHeader, deep, perOffset) => { | 
				
			||||
 | 
					    let offset = 0; | 
				
			||||
 | 
					    let cur = excelHeader[deep]; | 
				
			||||
 | 
					    if (!cur) { | 
				
			||||
 | 
					      cur = excelHeader[deep] = []; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    pushNull(cur, perOffset - cur.length); | 
				
			||||
 | 
					    for (let i = 0; i < headers.length; i++) { | 
				
			||||
 | 
					      const head = headers[i]; | 
				
			||||
 | 
					      cur.push(head.name); | 
				
			||||
 | 
					      if (head.hasOwnProperty('child') && Array.isArray(head.child) && head.child.length > 0) { | 
				
			||||
 | 
					        const childOffset = getHeader(head.child, excelHeader, deep + 1, cur.length - 1); | 
				
			||||
 | 
					        pushNull(cur, childOffset - 1); | 
				
			||||
 | 
					        offset += childOffset; | 
				
			||||
 | 
					      } else { | 
				
			||||
 | 
					        offset++; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return offset; | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const pushNull = (arr, count) => { | 
				
			||||
 | 
					    for (let i = 0; i < count; i++) { | 
				
			||||
 | 
					      arr.push(null); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  const fillNull = (arr) => { | 
				
			||||
 | 
					    const max = Math.max(...(arr.map((a) => a.length))); | 
				
			||||
 | 
					    arr.filter((e) => e.length < max).forEach((e) => pushNull(e, max - e.length)); | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  const doMerges = (arr) => { | 
				
			||||
 | 
					    // 要么横向合并 要么纵向合并
 | 
				
			||||
 | 
					    const deep = arr.length; | 
				
			||||
 | 
					    const merges = []; | 
				
			||||
 | 
					    for (let y = 0; y < deep; y++) { | 
				
			||||
 | 
					      // 先处理横向合并
 | 
				
			||||
 | 
					      const row = arr[y]; | 
				
			||||
 | 
					      let colSpan = 0; | 
				
			||||
 | 
					      for (let x = 0; x < row.length; x++) { | 
				
			||||
 | 
					        if (row[x] === null) { | 
				
			||||
 | 
					          colSpan++; | 
				
			||||
 | 
					          if (((x + 1) === row.length) && (colSpan > 0 && x > colSpan)) { | 
				
			||||
 | 
					            merges.push({ s: { r: y, c: x - colSpan }, e: { r: y, c: x } }); | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        } else if (colSpan > 0 && x > colSpan) { | 
				
			||||
 | 
					          merges.push({ s: { r: y, c: x - colSpan - 1 }, e: { r: y, c: x - 1 } }); | 
				
			||||
 | 
					          colSpan = 0; | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					          colSpan = 0; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    // 再处理纵向合并
 | 
				
			||||
 | 
					    const colLength = arr[0].length; | 
				
			||||
 | 
					    for (let x = 0; x < colLength; x++) { | 
				
			||||
 | 
					      let rowSpan = 0; | 
				
			||||
 | 
					      for (let y = 0; y < deep; y++) { | 
				
			||||
 | 
					        if (arr[y][x] != null) { | 
				
			||||
 | 
					          rowSpan = 0; | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					          rowSpan++; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					      if (rowSpan > 0) { | 
				
			||||
 | 
					        merges.push({ s: { r: deep - rowSpan - 1, c: x }, e: { r: deep - 1, c: x } }); | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return merges; | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  // 内容暂只出了纵向合并
 | 
				
			||||
 | 
					  const doContetMerges = (arr, headerLength) => { | 
				
			||||
 | 
					    const deep = arr.length; | 
				
			||||
 | 
					    const merges = []; | 
				
			||||
 | 
					    // 处理纵向合并
 | 
				
			||||
 | 
					    const colLength = arr[0].length; | 
				
			||||
 | 
					    for (let x = 0; x < colLength; x++) { | 
				
			||||
 | 
					      let rowSpan = 0; | 
				
			||||
 | 
					      const mergY = 0; | 
				
			||||
 | 
					      for (let y = 0; y < deep; y++) { | 
				
			||||
 | 
					        if (rowSpan > 0) { | 
				
			||||
 | 
					          // 如果还有null 继续加
 | 
				
			||||
 | 
					          if (arr[y][x] === null) { | 
				
			||||
 | 
					            rowSpan += 1; | 
				
			||||
 | 
					          } else { | 
				
			||||
 | 
					            // 不为null 增加merge
 | 
				
			||||
 | 
					            merges.push({ s: { r: headerLength + (y - rowSpan - 1), c: x }, e: { r: headerLength + y - 1, c: x } }); | 
				
			||||
 | 
					            rowSpan = 0; | 
				
			||||
 | 
					          } | 
				
			||||
 | 
					        } else if (arr[y][x] === null) { | 
				
			||||
 | 
					          rowSpan += 1; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					      if (rowSpan > 0) { | 
				
			||||
 | 
					        merges.push({ s: { r: headerLength + (deep - rowSpan - 1), c: x }, e: { r: headerLength + deep - 1, c: x } }); | 
				
			||||
 | 
					        rowSpan = 0; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    return merges; | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  const exportMergeExcel = async () => { | 
				
			||||
 | 
					    setExportLoading(true); | 
				
			||||
 | 
					    const { | 
				
			||||
 | 
					      column, data, fileName, exportUrl, exportQuery, exportBody, requestType, header, showYearMouth, | 
				
			||||
 | 
					    } = props || {}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    let resultData = []; | 
				
			||||
 | 
					    if (exportUrl) { | 
				
			||||
 | 
					      resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { | 
				
			||||
 | 
					        // 数据接口返回的结果 如果是对象 必须把返回数组放入rows
 | 
				
			||||
 | 
					        if (typeof data === 'object' && data.rows) { | 
				
			||||
 | 
					          return data.rows; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data; | 
				
			||||
 | 
					      }, (err) => { | 
				
			||||
 | 
					        message.error('获取数据失败,导出失败!'); | 
				
			||||
 | 
					      }) : await Request.get(exportUrl, exportQuery || {}).then((data) => { | 
				
			||||
 | 
					        if (typeof data === 'object' && data.rows) { | 
				
			||||
 | 
					          return data.rows; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data; | 
				
			||||
 | 
					      }, (err) => { | 
				
			||||
 | 
					        message.error('获取数据失败,导出失败!'); | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					      if (!resultData) { | 
				
			||||
 | 
					        return; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					      resultData = data; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    const excelHeader = []; | 
				
			||||
 | 
					    getHeader(column, excelHeader, 0, 0); | 
				
			||||
 | 
					    fillNull(excelHeader); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // console.log(excelHeader);
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const loopData = getDataSource(column, resultData); | 
				
			||||
 | 
					    // console.log(loopData)
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const dataToAoa = []; | 
				
			||||
 | 
					    getFlatData(column, loopData, dataToAoa, 0); | 
				
			||||
 | 
					    fillNull(dataToAoa); | 
				
			||||
 | 
					    // console.log(dataToAoa);
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const aoa = [].concat(excelHeader, dataToAoa); | 
				
			||||
 | 
					    // console.log(aoa)
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const headerMerges = doMerges(excelHeader); | 
				
			||||
 | 
					    const contentMerages = doContetMerges(dataToAoa, excelHeader.length); | 
				
			||||
 | 
					    const merges = [].concat(headerMerges, contentMerages); | 
				
			||||
 | 
					    // console.log(contentMerages)
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // let opts = {
 | 
				
			||||
 | 
					    //     defaultCellStyle: {
 | 
				
			||||
 | 
					    //         font: { name: "宋体", sz: 11, color: { auto: 1 } },
 | 
				
			||||
 | 
					    //         border: {
 | 
				
			||||
 | 
					    //             color: { auto: 1 }
 | 
				
			||||
 | 
					    //         },
 | 
				
			||||
 | 
					    //         alignment: {
 | 
				
			||||
 | 
					    //             /// 自动换行
 | 
				
			||||
 | 
					    //             wrapText: 1,
 | 
				
			||||
 | 
					    //             // 居中
 | 
				
			||||
 | 
					    //             horizontal: "center",
 | 
				
			||||
 | 
					    //             vertical: "center",
 | 
				
			||||
 | 
					    //             indent: 0
 | 
				
			||||
 | 
					    //         }
 | 
				
			||||
 | 
					    //    }
 | 
				
			||||
 | 
					    // }
 | 
				
			||||
 | 
					    const sheet = XLSX.utils.aoa_to_sheet(aoa); | 
				
			||||
 | 
					    // let newSheet = {};
 | 
				
			||||
 | 
					    // for (let [key, value] of Object.entries(sheet)) {
 | 
				
			||||
 | 
					    //     if(key == '!ref'){
 | 
				
			||||
 | 
					    //         newSheet[key] = value
 | 
				
			||||
 | 
					    //     }else if(typeof value === 'object'){
 | 
				
			||||
 | 
					    //         newSheet[key] = {
 | 
				
			||||
 | 
					    //             ...value,
 | 
				
			||||
 | 
					    //             s: opts.defaultCellStyle
 | 
				
			||||
 | 
					    //         }
 | 
				
			||||
 | 
					    //     }
 | 
				
			||||
 | 
					    // }
 | 
				
			||||
 | 
					    const wpx = column.map((c) => ({ | 
				
			||||
 | 
					      wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, | 
				
			||||
 | 
					    })); | 
				
			||||
 | 
					    sheet['!cols'] = wpx; | 
				
			||||
 | 
					    sheet['!merges'] = merges; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 构建 workbook 对象
 | 
				
			||||
 | 
					    const workbook = XLSX.utils.book_new(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const time = moment().format('YYYY-MM-DD'); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    XLSX.utils.book_append_sheet(workbook, sheet, 'mySheet'); | 
				
			||||
 | 
					    // 导出 Excel
 | 
				
			||||
 | 
					    XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : '导出数据.xlsx'); | 
				
			||||
 | 
					    setExportLoading(false); | 
				
			||||
 | 
					    // message.success(`成功导出了 ${loopData.length || 0} 条数据`);
 | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const exportProExcel = async () => { | 
				
			||||
 | 
					    setExportLoading(true); | 
				
			||||
 | 
					    const { | 
				
			||||
 | 
					      column, data, fileName, exportUrl, exportQuery, exportBody, requestType, showYearMouth, | 
				
			||||
 | 
					    } = props || {}; | 
				
			||||
 | 
					    let resultData = []; | 
				
			||||
 | 
					    if (exportUrl) { | 
				
			||||
 | 
					      resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { | 
				
			||||
 | 
					        // 数据接口返回的结果 如果是对象 必须把返回数组放入rows
 | 
				
			||||
 | 
					        if (typeof data === 'object') { | 
				
			||||
 | 
					          return data.data ? data.data : data.rows; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data; | 
				
			||||
 | 
					      }, (err) => { | 
				
			||||
 | 
					        message.error('获取数据失败,导出失败!'); | 
				
			||||
 | 
					      }) : await Request.get(exportUrl, exportQuery || {}).then((data) => { | 
				
			||||
 | 
					        if (showYearMouth) { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        if (typeof data === 'object' && data.rows) { | 
				
			||||
 | 
					          return data.rows; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data; | 
				
			||||
 | 
					      }, (err) => { | 
				
			||||
 | 
					        message.error('获取数据失败,导出失败!'); | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					      if (!resultData) { | 
				
			||||
 | 
					        return; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					      resultData = data; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const loopData = getDataSource(column, resultData); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    let content = ''; | 
				
			||||
 | 
					    let header = '<tr>'; | 
				
			||||
 | 
					    // header += `<th><div>序号</div></th>`;
 | 
				
			||||
 | 
					    column.map((colum) => { | 
				
			||||
 | 
					      header += `<th><div>${colum.name}</div></th>`; | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					    header += '</tr>'; | 
				
			||||
 | 
					    loopData.map((data) => { | 
				
			||||
 | 
					      content += '<tr>'; | 
				
			||||
 | 
					      column.map((c) => { | 
				
			||||
 | 
					        if (c.style) { | 
				
			||||
 | 
					          content += `<th style="${c.style}"><div>${data[c.dataIndex || c.key]}</div></th>`; | 
				
			||||
 | 
					        } else { | 
				
			||||
 | 
					          content += `<th><div>${data[c.dataIndex || c.key]}</div></th>`; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					      content += '</tr>'; | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const exportTable = `\uFEFF
 | 
				
			||||
 | 
					                <table style='text-alagin:center' border="1"> | 
				
			||||
 | 
					                    ${header} | 
				
			||||
 | 
					                    ${content} | 
				
			||||
 | 
					                </table> | 
				
			||||
 | 
					            `;
 | 
				
			||||
 | 
					    const time = moment().format('YYYY-MM-DD'); | 
				
			||||
 | 
					    const tempStrs = new Blob([exportTable], { type: 'text/xls' }); | 
				
			||||
 | 
					    FileSaver.saveAs(tempStrs, fileName ? `${fileName}-${time}.xls` : '导出数据.xls'); | 
				
			||||
 | 
					    setExportLoading(false); | 
				
			||||
 | 
					    // message.success(`成功导出了 ${loopData.length || 0} 条数据`);
 | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const exportExcel = async () => { | 
				
			||||
 | 
					    setExportLoading(true); | 
				
			||||
 | 
					    const { | 
				
			||||
 | 
					      column, data, fileName, exportUrl, exportQuery, exportBody, requestType, | 
				
			||||
 | 
					    } = props || {}; | 
				
			||||
 | 
					    const _headers = column | 
				
			||||
 | 
					      .map((item, i) => ({ key: item.key, title: item.name, position: String.fromCharCode(65 + i) + 1 })) | 
				
			||||
 | 
					      .reduce((prev, next) => ({ ...prev, [next.position]: { key: next.key, v: next.title } }), {}); | 
				
			||||
 | 
					    let resultData = []; | 
				
			||||
 | 
					    if (exportUrl) { | 
				
			||||
 | 
					      resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { | 
				
			||||
 | 
					        // 数据接口返回的结果 如果是对象 必须把返回数组放入rows
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        if (typeof data === 'object' && (data.rows || data.data)) { | 
				
			||||
 | 
					          return data.data ? data.data : data.rows; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data; | 
				
			||||
 | 
					      }, (err) => { | 
				
			||||
 | 
					        message.error('获取数据失败,导出失败!'); | 
				
			||||
 | 
					      }) : await Request.get(exportUrl, exportQuery || {}).then((data) => { | 
				
			||||
 | 
					        if (typeof data === 'object' && data.rows) { | 
				
			||||
 | 
					          return data.rows; | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data; | 
				
			||||
 | 
					      }, (err) => { | 
				
			||||
 | 
					        message.error('获取数据失败,导出失败!'); | 
				
			||||
 | 
					      }); | 
				
			||||
 | 
					      if (!resultData) { | 
				
			||||
 | 
					        return; | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    } else { | 
				
			||||
 | 
					      resultData = data; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const loopDate = getDataSource(column, resultData); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const wpx = column.map((c) => ({ | 
				
			||||
 | 
					      wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, | 
				
			||||
 | 
					    })); | 
				
			||||
 | 
					    if (!(loopDate.length > 0)) { | 
				
			||||
 | 
					      setExportLoading(false); | 
				
			||||
 | 
					      return; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					    const _data = loopDate | 
				
			||||
 | 
					      .map((item, i) => column.map((key, j) => ({ content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) }))) | 
				
			||||
 | 
					      // 对刚才的结果进行降维处理(二维数组变成一维数组)
 | 
				
			||||
 | 
					      .reduce((prev, next) => prev.concat(next)) | 
				
			||||
 | 
					      // 转换成 worksheet 需要的结构
 | 
				
			||||
 | 
					      .reduce((prev, next) => ({ ...prev, [next.position]: { v: next.content } }), {}); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 合并 column 和 data
 | 
				
			||||
 | 
					    const output = { ..._headers, ..._data }; | 
				
			||||
 | 
					    // 获取所有单元格的位置
 | 
				
			||||
 | 
					    const outputPos = Object.keys(output); | 
				
			||||
 | 
					    // 计算出范围 ,["A1",..., "H2"]
 | 
				
			||||
 | 
					    const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 构建 workbook 对象
 | 
				
			||||
 | 
					    const workbook = { | 
				
			||||
 | 
					      SheetNames: ['mySheet'], | 
				
			||||
 | 
					      Sheets: { | 
				
			||||
 | 
					        mySheet: { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					          ...output, | 
				
			||||
 | 
					          '!ref': ref, | 
				
			||||
 | 
					          '!cols': wpx, | 
				
			||||
 | 
					        }, | 
				
			||||
 | 
					      }, | 
				
			||||
 | 
					    }; | 
				
			||||
 | 
					    const time = moment().format('YYYY-MM-DD'); | 
				
			||||
 | 
					    // 导出 Excel
 | 
				
			||||
 | 
					    XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : '导出数据.xlsx'); | 
				
			||||
 | 
					    setExportLoading(false); | 
				
			||||
 | 
					    // message.success(`成功导出了 ${loopDate.length || 0} 条数据`);
 | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  const exportTemplete = async () => { | 
				
			||||
 | 
					    const { importTemColumn, importTemData, fileName } = props || {}; | 
				
			||||
 | 
					    const _headers = importTemColumn | 
				
			||||
 | 
					      .map((item, i) => { | 
				
			||||
 | 
					        let group = 0; // 用于处理Z1的时候,重计算AA1
 | 
				
			||||
 | 
					        if (parseInt(i / 26) > group) { | 
				
			||||
 | 
					          group = parseInt(i / 26); | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        if (group > 0) { // AA1 BA1 CA1
 | 
				
			||||
 | 
					          const position = String.fromCharCode(65 + (group - 1)); | 
				
			||||
 | 
					          return { key: item.key, title: item.name, position: position + String.fromCharCode(65 + (i % 26)) + 1 }; | 
				
			||||
 | 
					        } return { key: item.key, title: item.name, position: String.fromCharCode(65 + i) + 1 }; | 
				
			||||
 | 
					      }) | 
				
			||||
 | 
					      .reduce((prev, next) => ({ ...prev, [next.position]: { key: next.key, v: next.title } }), {}); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const loopDate = getDataSource(importTemColumn, importTemData); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    const wpx = importTemColumn.map((c) => ({ | 
				
			||||
 | 
					      wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, | 
				
			||||
 | 
					    })); | 
				
			||||
 | 
					    const _data = loopDate.length ? loopDate | 
				
			||||
 | 
					      .map((item, i) => importTemColumn.map((key, j) => ({ content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) }))) | 
				
			||||
 | 
					      // 对刚才的结果进行降维处理(二维数组变成一维数组)
 | 
				
			||||
 | 
					      .reduce((prev, next) => prev.concat(next)) | 
				
			||||
 | 
					      // 转换成 worksheet 需要的结构
 | 
				
			||||
 | 
					      .reduce((prev, next) => ({ ...prev, [next.position]: { v: next.content } }), {}) : []; | 
				
			||||
 | 
					    // 合并 column 和 data
 | 
				
			||||
 | 
					    const output = { ..._headers, ..._data }; | 
				
			||||
 | 
					    // 获取所有单元格的位置
 | 
				
			||||
 | 
					    const outputPos = Object.keys(output); | 
				
			||||
 | 
					    // 计算出范围 ,["A1",..., "H2"]
 | 
				
			||||
 | 
					    const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    // 构建 workbook 对象
 | 
				
			||||
 | 
					    const workbook = { | 
				
			||||
 | 
					      SheetNames: ['mySheet'], | 
				
			||||
 | 
					      Sheets: { | 
				
			||||
 | 
					        mySheet: { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					          ...output, | 
				
			||||
 | 
					          '!ref': ref, | 
				
			||||
 | 
					          '!cols': wpx, | 
				
			||||
 | 
					        }, | 
				
			||||
 | 
					      }, | 
				
			||||
 | 
					    }; | 
				
			||||
 | 
					    // 导出 Excel
 | 
				
			||||
 | 
					    XLSX.writeFile(workbook, fileName ? `${fileName}-导入模板.xlsx` : '导入模板.xlsx'); | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					  const tips = (type) => { | 
				
			||||
 | 
					    const { tips, templeteBth = true } = props; | 
				
			||||
 | 
					    const description = ( | 
				
			||||
 | 
					      <div className="export-import"> | 
				
			||||
 | 
					        {tips && tips} | 
				
			||||
 | 
					        <Row gutter={16}> | 
				
			||||
 | 
					          <Col span={12}> | 
				
			||||
 | 
					            <Form form={form} initialValues={{}}> | 
				
			||||
 | 
					              <Form.Item name="import-file"> | 
				
			||||
 | 
					                <Input className="file-uploader" type="file" accept=".xlsx, .xls" onChange={(e) => importExcel(e, type)} /> | 
				
			||||
 | 
					                <Button style={props.btnStyle} className={props.btnClass} loading={importLoading}> | 
				
			||||
 | 
					                  选择文件 | 
				
			||||
 | 
					                </Button> | 
				
			||||
 | 
					              </Form.Item> | 
				
			||||
 | 
					            </Form> | 
				
			||||
 | 
					          </Col> | 
				
			||||
 | 
					          {templeteBth && ( | 
				
			||||
 | 
					            <Col span={12}> | 
				
			||||
 | 
					              <Button style={props.btnStyle} className={props.btnClass} onClick={exportTemplete}> | 
				
			||||
 | 
					                模板下载 | 
				
			||||
 | 
					              </Button> | 
				
			||||
 | 
					            </Col> | 
				
			||||
 | 
					          )} | 
				
			||||
 | 
					        </Row> | 
				
			||||
 | 
					      </div> | 
				
			||||
 | 
					    ); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    notification.info({ | 
				
			||||
 | 
					      message: '支持 .xlsx、.xls 格式的文件', | 
				
			||||
 | 
					      description, | 
				
			||||
 | 
					      key: 'import-notification', | 
				
			||||
 | 
					      duration: null, | 
				
			||||
 | 
					    }); | 
				
			||||
 | 
					  }; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					  return ( | 
				
			||||
 | 
					    <Space> | 
				
			||||
 | 
					      { | 
				
			||||
 | 
					        props.import && ( | 
				
			||||
 | 
					          <Button style={props.btnStyle} className={props.btnClass} loading={importLoading} onClick={tips}> | 
				
			||||
 | 
					            {props.importBtnName || '导入'} | 
				
			||||
 | 
					          </Button> | 
				
			||||
 | 
					        ) | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					      { | 
				
			||||
 | 
					        props.export && ( | 
				
			||||
 | 
					          <Tooltip placement="top" title={props.exportBtnTips || '默认导出所有数据'}> | 
				
			||||
 | 
					            <Button style={props.btnStyle} className={props.btnClass} loading={exportLoading} onClick={props.exportType === 'pro' ? exportProExcel : exportExcel}> | 
				
			||||
 | 
					              {props.exportBtnName || '导出'} | 
				
			||||
 | 
					            </Button> | 
				
			||||
 | 
					          </Tooltip> | 
				
			||||
 | 
					        ) | 
				
			||||
 | 
					      } | 
				
			||||
 | 
					    </Space> | 
				
			||||
 | 
					  ); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					ExportAndImport.propTypes = { | 
				
			||||
 | 
					  export: PropTypes.bool, // 是否显示导出按钮
 | 
				
			||||
 | 
					  exportBtnName: PropTypes.string, // 导出按钮文字
 | 
				
			||||
 | 
					  importBtnName: PropTypes.string, // 导入按钮文字
 | 
				
			||||
 | 
					  import: PropTypes.bool, // 是否显示导入按钮
 | 
				
			||||
 | 
					  variedImport: PropTypes.bool, // 是否显示多样导入
 | 
				
			||||
 | 
					  variedImportDisable: PropTypes.bool, // 多样导入禁用
 | 
				
			||||
 | 
					  variedImportBtnName: PropTypes.string, // 多样导入文字
 | 
				
			||||
 | 
					  column: PropTypes.array, // 导出显示的header数组 兼容antd column 可直接拿table的column使用  注:column每列的属性wpx设置导出的execl每列的宽度值 默认 100
 | 
				
			||||
 | 
					  data: PropTypes.array, // 导出的数据 兼容antd table 数组嵌套处理
 | 
				
			||||
 | 
					  exportUrl: PropTypes.string, // 导出数据从接口获取的url地址   返回的数据1、数组必须支持column的设置 ,2、如果是对象,数组需放在rows属性上
 | 
				
			||||
 | 
					  exportBody: PropTypes.object, // 导出数据接口body参数
 | 
				
			||||
 | 
					  exportQuery: PropTypes.object, // 导出数据从接口获取的url地址上的参数
 | 
				
			||||
 | 
					  exportBtnTips: PropTypes.string, // 导出按钮tips文字提示
 | 
				
			||||
 | 
					  importUrl: PropTypes.string, // 导入接口url
 | 
				
			||||
 | 
					  importQuery: PropTypes.object, // 导入接口url地址上的参数
 | 
				
			||||
 | 
					  btnClass: PropTypes.string, // 按钮className
 | 
				
			||||
 | 
					  btnStyle: PropTypes.object, // 按钮style
 | 
				
			||||
 | 
					  tips: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), // 上传文件提示的信息
 | 
				
			||||
 | 
					  onImportSucess: PropTypes.func, // 上传成功后 返回处理函数
 | 
				
			||||
 | 
					  importTemColumn: PropTypes.array, // 导入模板设置 头部字段数组
 | 
				
			||||
 | 
					  importTemData: PropTypes.array, // 导入模板默认数据
 | 
				
			||||
 | 
					  requestType: PropTypes.string, // 请求类型
 | 
				
			||||
 | 
					  importDataCallback: PropTypes.func, // 上传后数据返回
 | 
				
			||||
 | 
					  templeteBth: PropTypes.bool, // 模板按钮
 | 
				
			||||
 | 
					  importRequest: PropTypes.bool, // 请求导入接口,false时搭配importDataCallback,
 | 
				
			||||
 | 
					  exportType: PropTypes.string, // 导出执行的函数名
 | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					export default ExportAndImport; | 
				
			||||
@ -0,0 +1,13 @@ | 
				
			|||||
 | 
					.export-import { | 
				
			||||
 | 
					    .file-uploader { | 
				
			||||
 | 
					      position: absolute; | 
				
			||||
 | 
					      width: 100%; | 
				
			||||
 | 
					      height: 100%; | 
				
			||||
 | 
					      top: 0; | 
				
			||||
 | 
					      left: 0; | 
				
			||||
 | 
					      outline: none; | 
				
			||||
 | 
					      opacity: 0; | 
				
			||||
 | 
					      background-color: transparent; | 
				
			||||
 | 
					      z-index: 10; | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					  } | 
				
			||||