@ -0,0 +1,36 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
const { simpleExcelDown } = require('../../../../utils/xlsxDownload'); | 
				
			|||
 | 
				
			|||
async function dataExport (ctx) { | 
				
			|||
    try { | 
				
			|||
        // const models = ctx.fs.dc.models;
 | 
				
			|||
        // const { userId } = ctx.fs.api
 | 
				
			|||
        // const { ids } = ctx.query;
 | 
				
			|||
 | 
				
			|||
        // const exportData = await models.BusCar.destroy({
 | 
				
			|||
        //     where: {
 | 
				
			|||
        //         id: { $in: ids.split(',') }
 | 
				
			|||
        //     }
 | 
				
			|||
        // })
 | 
				
			|||
 | 
				
			|||
        // const fileName = `摄像头信息列表_${userId}_${moment().format('YYYYMMDDHHmmss')}` + '.csv'
 | 
				
			|||
        // const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName })
 | 
				
			|||
        // const fileData = fs.readFileSync(filePath);
 | 
				
			|||
 | 
				
			|||
        // ctx.status = 200;
 | 
				
			|||
        // ctx.set('Content-Type', 'application/x-xls');
 | 
				
			|||
        // ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName));
 | 
				
			|||
        // ctx.body = fileData;
 | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            message: typeof error == 'string' ? error : undefined | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
module.exports = { | 
				
			|||
    dataExport | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,77 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
async function publicityGet (ctx) { | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const { enable } = ctx.query; | 
				
			|||
        let findOption = { | 
				
			|||
            where: {}, | 
				
			|||
            order: [['id', 'DESC']] | 
				
			|||
        } | 
				
			|||
        if (enable) { | 
				
			|||
            findOption.where.enable = true | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        const roadRes = await models.Publicity.findAll(findOption) | 
				
			|||
 | 
				
			|||
        ctx.status = 200; | 
				
			|||
        ctx.body = roadRes | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            message: typeof error == 'string' ? error : undefined | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function publicityEdit (ctx) { | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const data = ctx.request.body; | 
				
			|||
 | 
				
			|||
        if (!data.publicityId) { | 
				
			|||
            await models.Publicity.create(data) | 
				
			|||
        } else { | 
				
			|||
            await models.Publicity.update( | 
				
			|||
                data, { | 
				
			|||
                where: { | 
				
			|||
                    id: data.publicityId | 
				
			|||
                } | 
				
			|||
            }) | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        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 | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function publicityDel (ctx) { | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const { publicityId } = ctx.params; | 
				
			|||
 | 
				
			|||
        await models.Publicity.destroy({ | 
				
			|||
            where: { | 
				
			|||
                id: publicityId | 
				
			|||
            } | 
				
			|||
        }) | 
				
			|||
 | 
				
			|||
        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 = { | 
				
			|||
    publicityGet, publicityEdit, publicityDel, | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,52 @@ | 
				
			|||
/* eslint-disable*/ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
module.exports = dc => { | 
				
			|||
    const DataTypes = dc.ORM; | 
				
			|||
    const sequelize = dc.orm; | 
				
			|||
    const Publicity = sequelize.define("publicity", { | 
				
			|||
        id: { | 
				
			|||
            type: DataTypes.INTEGER, | 
				
			|||
            allowNull: false, | 
				
			|||
            defaultValue: null, | 
				
			|||
            comment: null, | 
				
			|||
            primaryKey: true, | 
				
			|||
            field: "id", | 
				
			|||
            autoIncrement: true, | 
				
			|||
            unique: "publicity_id_uindex" | 
				
			|||
        }, | 
				
			|||
        name: { | 
				
			|||
            type: DataTypes.STRING, | 
				
			|||
            allowNull: false, | 
				
			|||
            defaultValue: null, | 
				
			|||
            comment: null, | 
				
			|||
            primaryKey: false, | 
				
			|||
            field: "name", | 
				
			|||
            autoIncrement: false | 
				
			|||
        }, | 
				
			|||
        video: { | 
				
			|||
            type: DataTypes.ARRAY(DataTypes.INTEGER), | 
				
			|||
            allowNull: true, | 
				
			|||
            defaultValue: null, | 
				
			|||
            comment: null, | 
				
			|||
            primaryKey: false, | 
				
			|||
            field: "video", | 
				
			|||
            autoIncrement: false | 
				
			|||
        }, | 
				
			|||
        enable: { | 
				
			|||
            type: DataTypes.BOOLEAN, | 
				
			|||
            allowNull: false, | 
				
			|||
            defaultValue: true, | 
				
			|||
            comment: null, | 
				
			|||
            primaryKey: false, | 
				
			|||
            field: "enable", | 
				
			|||
            autoIncrement: false | 
				
			|||
        } | 
				
			|||
    }, { | 
				
			|||
        tableName: "publicity", | 
				
			|||
        comment: "", | 
				
			|||
        indexes: [] | 
				
			|||
    }); | 
				
			|||
    dc.models.Publicity = Publicity; | 
				
			|||
    return Publicity; | 
				
			|||
}; | 
				
			|||
@ -0,0 +1,77 @@ | 
				
			|||
'use strict'; | 
				
			|||
const fs = require('fs'); | 
				
			|||
const xlsx = require('better-xlsx'); | 
				
			|||
const path = require('path') | 
				
			|||
const moment = require('moment') | 
				
			|||
 | 
				
			|||
//递归创建目录 同步方法  
 | 
				
			|||
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]; | 
				
			|||
            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 | 
				
			|||
} | 
				
			|||
module.exports = { | 
				
			|||
    simpleExcelDown, | 
				
			|||
    makeDir | 
				
			|||
} | 
				
			|||
@ -0,0 +1,19 @@ | 
				
			|||
pipeline { | 
				
			|||
    agent { | 
				
			|||
        node{ | 
				
			|||
            label 'jnlp-slave' | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
     | 
				
			|||
    stages { | 
				
			|||
        stage('Highways4Good Api ......') { | 
				
			|||
            steps { | 
				
			|||
                sh 'switch-auth.sh  anxinyun'  | 
				
			|||
                buildName "#${BUILD_NUMBER}  ~/fs-cloud/${JOB_NAME}:${IMAGE_VERSION}" | 
				
			|||
                buildDescription "registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}" | 
				
			|||
                sh 'docker build -t registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION} ./api'  | 
				
			|||
                sh 'docker push registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}'  | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,19 @@ | 
				
			|||
pipeline { | 
				
			|||
    agent { | 
				
			|||
        node{ | 
				
			|||
            label 'jnlp-slave' | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
     | 
				
			|||
    stages { | 
				
			|||
        stage('Highways4Good Web......') { | 
				
			|||
            steps { | 
				
			|||
                sh 'switch-auth.sh  anxinyun'  | 
				
			|||
                buildName "#${BUILD_NUMBER}  ~/fs-cloud/${JOB_NAME}:${IMAGE_VERSION}" | 
				
			|||
                buildDescription "registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}" | 
				
			|||
                sh 'docker build -t registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION} ./web'  | 
				
			|||
                sh 'docker push registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}'  | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,17 @@ | 
				
			|||
{ | 
				
			|||
    // 使用 IntelliSense 了解相关属性。  | 
				
			|||
    // 悬停以查看现有属性的描述。 | 
				
			|||
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 | 
				
			|||
    "version": "0.2.0", | 
				
			|||
    "configurations": [ | 
				
			|||
        { | 
				
			|||
            "type": "node", | 
				
			|||
            "request": "launch", | 
				
			|||
            "name": "启动程序", | 
				
			|||
            "skipFiles": [ | 
				
			|||
                "<node_internals>/**" | 
				
			|||
            ], | 
				
			|||
            "program": "${workspaceFolder}\\index.js" | 
				
			|||
        } | 
				
			|||
    ] | 
				
			|||
} | 
				
			|||
| 
		 After Width: | Height: | Size: 205 KiB  | 
| 
		 After Width: | Height: | Size: 183 KiB  | 
| 
		 After Width: | Height: | Size: 242 KiB  | 
| 
		 After Width: | Height: | Size: 858 KiB  | 
| 
		 After Width: | Height: | Size: 808 KiB  | 
| 
		 After Width: | Height: | Size: 234 KiB  | 
| 
		 After Width: | Height: | Size: 895 KiB  | 
| 
		 After Width: | Height: | Size: 220 KiB  | 
| 
		 After Width: | Height: | Size: 987 KiB  | 
| 
		 After Width: | Height: | Size: 260 KiB  | 
| 
		 After Width: | Height: | Size: 970 KiB  | 
| 
		 After Width: | Height: | Size: 759 KiB  | 
| 
		 After Width: | Height: | Size: 166 KiB  | 
| 
		 After Width: | Height: | Size: 108 KiB  | 
| 
		 After Width: | Height: | Size: 216 KiB  | 
| 
		 After Width: | Height: | Size: 762 KiB  | 
| 
		 After Width: | Height: | Size: 206 KiB  | 
| 
		 After Width: | Height: | Size: 710 KiB  | 
| 
		 After Width: | Height: | Size: 264 KiB  | 
| 
		 After Width: | Height: | Size: 557 KiB  | 
| 
		 After Width: | Height: | Size: 252 KiB  | 
| 
		 After Width: | Height: | Size: 622 KiB  | 
| 
		 After Width: | Height: | Size: 744 KiB  | 
| 
		 After Width: | Height: | Size: 232 KiB  | 
| 
		 After Width: | Height: | Size: 408 KiB  | 
| 
		 After Width: | Height: | Size: 416 KiB  | 
| 
		 After Width: | Height: | Size: 248 KiB  | 
| 
		 After Width: | Height: | Size: 893 KiB  | 
| 
		 After Width: | Height: | Size: 214 KiB  | 
| 
		 After Width: | Height: | Size: 924 KiB  | 
| 
		 After Width: | Height: | Size: 211 KiB  | 
| 
		 After Width: | Height: | Size: 932 KiB  | 
| 
		 After Width: | Height: | Size: 255 KiB  | 
| 
		 After Width: | Height: | Size: 932 KiB  | 
| 
		 After Width: | Height: | Size: 269 KiB  | 
| 
		 After Width: | Height: | Size: 211 KiB  | 
| 
		 After Width: | Height: | Size: 899 KiB  | 
| 
		 After Width: | Height: | Size: 251 KiB  | 
| 
		 After Width: | Height: | Size: 219 KiB  | 
| 
		 After Width: | Height: | Size: 227 KiB  | 
| 
		 After Width: | Height: | Size: 797 KiB  | 
| 
		 After Width: | Height: | Size: 258 KiB  | 
| 
		 After Width: | Height: | Size: 874 KiB  | 
| 
		 After Width: | Height: | Size: 227 KiB  | 
| 
		 After Width: | Height: | Size: 1008 KiB  | 
@ -0,0 +1,132 @@ | 
				
			|||
try { | 
				
			|||
    const { Pool, Client } = require('pg') | 
				
			|||
    const request = require('superagent'); | 
				
			|||
    const Hex = require('crypto-js/enc-hex'); | 
				
			|||
    const MD5 = require('crypto-js/md5'); | 
				
			|||
    const XLSX = require('xlsx') | 
				
			|||
    const path = require('path') | 
				
			|||
    const fs = require("fs"); | 
				
			|||
    const qiniu = require('qiniu'); | 
				
			|||
    const uuidv4 = require('uuid/v4'); | 
				
			|||
 | 
				
			|||
    // 连接数据库
 | 
				
			|||
    const pool = new Pool({ | 
				
			|||
        user: 'postgres', | 
				
			|||
        host: '10.8.30.32', | 
				
			|||
        database: 'highways4good', | 
				
			|||
        password: '123', | 
				
			|||
        port: 5432, | 
				
			|||
    }) | 
				
			|||
    // 7niu 验证
 | 
				
			|||
    const accessKey = 'XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5' | 
				
			|||
    const secretKey = 'yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa' | 
				
			|||
    const bucket = 'dev-highways4good' | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
    const fun = async () => { | 
				
			|||
        // note: we don't try/catch this because if connecting throws an exception
 | 
				
			|||
        // we don't need to dispose of the client (it will be undefined)
 | 
				
			|||
        const client = await pool.connect() | 
				
			|||
        try { | 
				
			|||
            await client.query('BEGIN') | 
				
			|||
 | 
				
			|||
            console.log(`开始`); | 
				
			|||
            const upload7niu = | 
				
			|||
                async (filePath, filename) => { | 
				
			|||
                    return new Promise((resolve, reject) => { | 
				
			|||
                        try { | 
				
			|||
                            const uploadPath = 'images' | 
				
			|||
                            // 7niu 鉴权
 | 
				
			|||
                            const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); | 
				
			|||
                            const config = { | 
				
			|||
                                scope: bucket, | 
				
			|||
                                // expires: 3600,
 | 
				
			|||
                                returnBody: '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}' | 
				
			|||
                            } | 
				
			|||
                            var putPolicy = new qiniu.rs.PutPolicy(config); | 
				
			|||
                            var uploadToken = putPolicy.uploadToken(mac); | 
				
			|||
                            // 上传文件
 | 
				
			|||
                            var formUploader = new qiniu.form_up.FormUploader(config); | 
				
			|||
                            var putExtra = new qiniu.form_up.PutExtra(); | 
				
			|||
                            let key = path.posix.join(uploadPath, uuidv4(), filename); | 
				
			|||
                            formUploader.putFile(uploadToken, key, filePath, putExtra, function (respErr, | 
				
			|||
                                respBody, respInfo) { | 
				
			|||
                                if (respErr) { | 
				
			|||
                                    reject(respErr); | 
				
			|||
                                    throw respErr; | 
				
			|||
                                } | 
				
			|||
                                if (respInfo.statusCode == 200) { | 
				
			|||
                                    console.log(respBody); | 
				
			|||
                                    let qnkey = respBody.key; | 
				
			|||
                                    resolve({ key: qnkey, url: `${qnkey}` }); | 
				
			|||
                                } else { | 
				
			|||
                                    console.log(respInfo.statusCode); | 
				
			|||
                                    console.log(respBody); | 
				
			|||
                                    reject(new Error('failed to upload.')); | 
				
			|||
                                } | 
				
			|||
                            }); | 
				
			|||
 | 
				
			|||
                        } catch (err) { | 
				
			|||
                            reject(err); | 
				
			|||
                        } | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
 | 
				
			|||
 | 
				
			|||
            // 读取数据文件
 | 
				
			|||
            let workbook = XLSX.readFile(path.join(__dirname, './data/work.xlsx')); | 
				
			|||
            let firstSheetName = workbook.SheetNames[0]; | 
				
			|||
            let worksheet = workbook.Sheets[firstSheetName]; | 
				
			|||
            let res = XLSX.utils.sheet_to_json(worksheet, { | 
				
			|||
                defval: '' | 
				
			|||
            }); | 
				
			|||
            // console.log(res);
 | 
				
			|||
            res.sort((a, b) => { return Date.parse(a['时间']) - Date.parse(b['时间']) }); | 
				
			|||
 | 
				
			|||
            // 读取全部图片
 | 
				
			|||
            let pic = []; | 
				
			|||
            fs.readdirSync(path.join(__dirname, '/data/pic')).forEach((filename) => { | 
				
			|||
                pic.push({ | 
				
			|||
                    path: `./data/pic/${filename}`, | 
				
			|||
                    name: filename | 
				
			|||
                }) | 
				
			|||
            }); | 
				
			|||
 | 
				
			|||
            for (let r of res) { | 
				
			|||
                console.log(r); | 
				
			|||
                let picList = pic.filter(p => { | 
				
			|||
                    const { name } = p | 
				
			|||
                    const no = name.split('-')[0] | 
				
			|||
                    return no == r['编号'] | 
				
			|||
                }) | 
				
			|||
                console.log(picList); | 
				
			|||
                // 将图片上传至 7niu
 | 
				
			|||
                let upPicUrl = []; | 
				
			|||
                for (let p of picList) { | 
				
			|||
                    const upRes = await upload7niu(path.join(__dirname, p.path), p.name) | 
				
			|||
                    console.log(upRes); | 
				
			|||
                    upPicUrl.push(upRes.url) | 
				
			|||
                } | 
				
			|||
                const roadSectionArr = r['路段'] ? r['路段'].split('至') : null | 
				
			|||
                const roadSection = roadSectionArr && roadSectionArr.length > 1 ? roadSectionArr : [null, null] | 
				
			|||
                await client.query(`INSERT INTO report (report_type, project_type, road, road_section_start, road_section_end,time,content,conserve_underway_pic) VALUES($1, $2, $3, $4, $5, $6, $7, $8) `, ['conserve', 'road', r['道路'], roadSection[0], roadSection[1], r['时间'], r['内容'], upPicUrl]) | 
				
			|||
                // break
 | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            // await client.query('ROLLBACK')
 | 
				
			|||
            await client.query('COMMIT') | 
				
			|||
            console.log('执行完毕~') | 
				
			|||
        } catch (e) { | 
				
			|||
            await client.query('ROLLBACK') | 
				
			|||
            console.log('执行错误~') | 
				
			|||
            throw e | 
				
			|||
        } finally { | 
				
			|||
            client.release(); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    fun() | 
				
			|||
} catch (error) { | 
				
			|||
    console.error(error) | 
				
			|||
} | 
				
			|||
@ -0,0 +1,20 @@ | 
				
			|||
{ | 
				
			|||
  "name": "appkey-generator", | 
				
			|||
  "version": "1.0.0", | 
				
			|||
  "description": "tool", | 
				
			|||
  "main": "index.js", | 
				
			|||
  "scripts": { | 
				
			|||
    "test": "mocha", | 
				
			|||
    "start": "set NODE_ENV=development&&node index" | 
				
			|||
  }, | 
				
			|||
  "author": "liu", | 
				
			|||
  "license": "ISC", | 
				
			|||
  "dependencies": { | 
				
			|||
    "crypto-js": "^4.1.1", | 
				
			|||
    "pg": "^7.18.2", | 
				
			|||
    "qiniu": "^7.7.0", | 
				
			|||
    "superagent": "^8.0.0", | 
				
			|||
    "uuid": "3.1.0", | 
				
			|||
    "xlsx": "^0.17.1" | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,3 @@ | 
				
			|||
export default { | 
				
			|||
	navigationBarTitleText: '修改密码' | 
				
			|||
} | 
				
			|||
@ -0,0 +1,64 @@ | 
				
			|||
import React, { useState } from 'react' | 
				
			|||
import Taro from '@tarojs/taro' | 
				
			|||
import { View, Input } from '@tarojs/components' | 
				
			|||
import { AtButton } from 'taro-ui' | 
				
			|||
import request from '@/services/request' | 
				
			|||
import { putPassword } from '@/services/api' | 
				
			|||
import './index.scss' | 
				
			|||
 | 
				
			|||
function Index() { | 
				
			|||
  const userInfo = Taro.getStorageSync('userInfo') || null; | 
				
			|||
  const [phone, setPhone] = useState(userInfo.phone) | 
				
			|||
  const [password, setPassword] = useState('') | 
				
			|||
  const [password2, setPassword2] = useState('') | 
				
			|||
 | 
				
			|||
  function confirm() { | 
				
			|||
    if (!password) { | 
				
			|||
      Taro.showToast({ title: '请输入密码' }) | 
				
			|||
      return | 
				
			|||
    } else if (password !== password2) { | 
				
			|||
      Taro.showToast({ title: '两次输入的密码不一致' }) | 
				
			|||
      return | 
				
			|||
    } else { | 
				
			|||
      Taro.showModal({ | 
				
			|||
        title: '提示', | 
				
			|||
        content: '确定修改吗', | 
				
			|||
        success: function (res) { | 
				
			|||
          if (res.confirm) { | 
				
			|||
            Taro.showLoading({ | 
				
			|||
              title: '修改中' | 
				
			|||
            }) | 
				
			|||
            request.put(putPassword(userInfo.id), { password }).then(res => { | 
				
			|||
              Taro.hideLoading() | 
				
			|||
              if (res.statusCode == 200 || res.statusCode == 204) { | 
				
			|||
                Taro.removeStorageSync('token') | 
				
			|||
                Taro.removeStorageSync('userInfo') | 
				
			|||
                Taro.reLaunch({ url: '/packages/changePassword/success/index' }) | 
				
			|||
              } | 
				
			|||
            }) | 
				
			|||
          } | 
				
			|||
        } | 
				
			|||
      }) | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <View className='page'> | 
				
			|||
      <View className='phone'> | 
				
			|||
        <View className='title'>手机号码:</View> | 
				
			|||
        <Input value={phone} disabled={true} /> | 
				
			|||
      </View> | 
				
			|||
      <View className='pswd'> | 
				
			|||
        <View className='title'>新的密码:</View> | 
				
			|||
        <Input value={password} onInput={e => setPassword(e.detail.value)} /> | 
				
			|||
      </View> | 
				
			|||
      <View className='pswd'> | 
				
			|||
        <View className='title'>再次输入新的密码:</View> | 
				
			|||
        <Input value={password2} onInput={e => setPassword2(e.detail.value)} /> | 
				
			|||
      </View> | 
				
			|||
      <AtButton className='btn' type='primary' onClick={confirm}>确认</AtButton> | 
				
			|||
    </View> | 
				
			|||
  ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default Index | 
				
			|||
@ -0,0 +1,35 @@ | 
				
			|||
page { | 
				
			|||
  background-color: #f6f6f6; | 
				
			|||
  font-size: 28px; | 
				
			|||
 | 
				
			|||
  .phone { | 
				
			|||
    height: 96px; | 
				
			|||
    background-color: #fff; | 
				
			|||
    margin: 20px auto; | 
				
			|||
    display: flex; | 
				
			|||
    justify-content: left; | 
				
			|||
    align-items: center; | 
				
			|||
 | 
				
			|||
    .title { | 
				
			|||
      margin-left: 30px; | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  .pswd { | 
				
			|||
    height: 96px; | 
				
			|||
    background-color: #fff; | 
				
			|||
    margin-bottom: 5px; | 
				
			|||
    display: flex; | 
				
			|||
    justify-content: left; | 
				
			|||
    align-items: center; | 
				
			|||
 | 
				
			|||
    .title { | 
				
			|||
      margin-left: 30px; | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  .btn { | 
				
			|||
    width: 70%; | 
				
			|||
    margin: 80px auto; | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,3 @@ | 
				
			|||
export default { | 
				
			|||
  navigationBarTitleText: '修改密码' | 
				
			|||
} | 
				
			|||
@ -0,0 +1,24 @@ | 
				
			|||
import React from 'react' | 
				
			|||
import Taro from '@tarojs/taro' | 
				
			|||
import { View, Image } from '@tarojs/components' | 
				
			|||
import { AtButton } from 'taro-ui' | 
				
			|||
import './index.scss' | 
				
			|||
import successIcon from '../../../static/img/changePassword/success.svg' | 
				
			|||
 | 
				
			|||
function Index() { | 
				
			|||
  function handleClick() { | 
				
			|||
    Taro.reLaunch({ url: '/pages/auth/login/login' }) | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <View> | 
				
			|||
      <View className='box'> | 
				
			|||
        <Image className='img' src={successIcon} /> | 
				
			|||
        <View className='text'>修改成功!</View> | 
				
			|||
      </View> | 
				
			|||
      <AtButton className='btn' type='primary' onClick={handleClick}>返回登录</AtButton> | 
				
			|||
    </View> | 
				
			|||
  ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default Index | 
				
			|||
@ -0,0 +1,26 @@ | 
				
			|||
page { | 
				
			|||
  background-color: #f6f6f6; | 
				
			|||
 | 
				
			|||
  .box { | 
				
			|||
    background-color: #fff; | 
				
			|||
    height: 360px; | 
				
			|||
    display: flex; | 
				
			|||
    flex-direction: column; | 
				
			|||
    justify-content: center; | 
				
			|||
    align-items: center; | 
				
			|||
 | 
				
			|||
    .img { | 
				
			|||
      width: 160px; | 
				
			|||
      height: 160px; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    .text { | 
				
			|||
      margin-top: 32px; | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  .btn { | 
				
			|||
    width: 70%; | 
				
			|||
    margin: 80px auto; | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
@ -0,0 +1,52 @@ | 
				
			|||
/* | 
				
			|||
* 输入框筛选选择器 | 
				
			|||
*/ | 
				
			|||
import React, { useState, useEffect } from 'react' | 
				
			|||
import { View, Picker, Image, Input, Text } from '@tarojs/components' | 
				
			|||
import arrowIcon from '../../../static/img/patrol/arrow-down.svg' | 
				
			|||
import './index.scss' | 
				
			|||
 | 
				
			|||
export default function InputPicker(props) { | 
				
			|||
  const { title, placeholder, selector, value, onInput, isView } = props | 
				
			|||
  const [curSelector, setCurSelector] = useState([]) | 
				
			|||
 | 
				
			|||
  useEffect(() => { | 
				
			|||
    setCurSelector(selector) | 
				
			|||
  }, []) | 
				
			|||
 | 
				
			|||
  function handleInput({ detail: { value: v } }) { | 
				
			|||
    onInput(v) | 
				
			|||
    if (v) { | 
				
			|||
      setCurSelector(selector.filter(item => item && item.includes(v))) | 
				
			|||
    } else { | 
				
			|||
      setCurSelector(selector) | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  const handlePickerChange = (e) => { | 
				
			|||
    onInput(curSelector[e.detail.value]) | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <View className='input-picker'> | 
				
			|||
      <View className='input-box'> | 
				
			|||
        <View className='title'><Text style={{ color: 'red' }}>* </Text>{title}</View> | 
				
			|||
        <Input | 
				
			|||
          className='input' | 
				
			|||
          type='text' | 
				
			|||
          placeholder={placeholder} | 
				
			|||
          border={false} | 
				
			|||
          value={value} | 
				
			|||
          onInput={handleInput} | 
				
			|||
          disabled={isView} | 
				
			|||
        /> | 
				
			|||
      </View> | 
				
			|||
      { | 
				
			|||
        !isView && | 
				
			|||
        <Picker mode='selector' range={curSelector} onChange={handlePickerChange}> | 
				
			|||
          <Image src={arrowIcon} className='img' /> | 
				
			|||
        </Picker> | 
				
			|||
      } | 
				
			|||
    </View> | 
				
			|||
  ) | 
				
			|||
} | 
				
			|||
@ -0,0 +1,30 @@ | 
				
			|||
.input-picker { | 
				
			|||
  display: flex; | 
				
			|||
  justify-content: space-between; | 
				
			|||
  height: 96px; | 
				
			|||
  align-items: center; | 
				
			|||
  background-color: #fff; | 
				
			|||
  margin-bottom: 5px; | 
				
			|||
 | 
				
			|||
  .input-box { | 
				
			|||
    padding: 12px 0; | 
				
			|||
    flex-grow: 1; | 
				
			|||
    display: flex; | 
				
			|||
    align-items: center; | 
				
			|||
 | 
				
			|||
    .title { | 
				
			|||
      margin-left: 12px; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    .input { | 
				
			|||
      margin-left: 20px; | 
				
			|||
      flex-grow: 1; | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  .img { | 
				
			|||
    width: 24px; | 
				
			|||
    height: 14px; | 
				
			|||
    margin: 0 30px; | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
| 
		 After Width: | Height: | Size: 1.6 KiB  | 
| 
		 After Width: | Height: | Size: 623 KiB  | 
| 
		 After Width: | Height: | Size: 14 KiB  | 
| 
		 After Width: | Height: | Size: 15 KiB  | 
@ -1,37 +1,33 @@ | 
				
			|||
<!DOCTYPE html> | 
				
			|||
<html> | 
				
			|||
 | 
				
			|||
<head> | 
				
			|||
  <meta charset="UTF-8" /> | 
				
			|||
  <title></title> | 
				
			|||
  <link rel="shortcut icon" href="/assets/images/favicon.ico" /> | 
				
			|||
    <link | 
				
			|||
      rel="stylesheet" | 
				
			|||
      type="text/css" | 
				
			|||
      href="/assets/font_sc/iconfont.css" | 
				
			|||
    /> | 
				
			|||
  <link rel="stylesheet" type="text/css" href="/assets/font_sc/iconfont.css" /> | 
				
			|||
  <link rel="stylesheet" href="/assets/fontziti/font.css" /> | 
				
			|||
  <script type="text/javascript"> | 
				
			|||
    window._AMapSecurityConfig = { | 
				
			|||
      securityJsCode: 'e955cd5ddfc3a752aa27d1e1c67d182d', | 
				
			|||
    } | 
				
			|||
  </script> | 
				
			|||
  <script | 
				
			|||
    src="https://webapi.amap.com/maps?v=2.0&key=00f9a29dedcdbd8befec3dfe0cef5003&plugin=AMap.Adaptor,AMap.Scale,AMap.ToolBar,AMap.DistrictSearch,AMap.Geocoder,AMap.CustomLayer,Map3D,ElasticMarker"></script> | 
				
			|||
  <script src="https://webapi.amap.com/loca?v=2.0.0&key=00f9a29dedcdbd8befec3dfe0cef5003"></script> | 
				
			|||
</head> | 
				
			|||
 | 
				
			|||
<body> | 
				
			|||
    <link | 
				
			|||
      rel="stylesheet/less" | 
				
			|||
      type="text/css" | 
				
			|||
      href="/assets/color.less" | 
				
			|||
      rel="external nofollow" | 
				
			|||
    /> | 
				
			|||
  <link rel="stylesheet/less" type="text/css" href="/assets/color.less" rel="external nofollow" /> | 
				
			|||
  <script> | 
				
			|||
    window.less = { | 
				
			|||
      async: false, | 
				
			|||
      env: "production", | 
				
			|||
    }; | 
				
			|||
  </script> | 
				
			|||
    <script | 
				
			|||
      type="text/javascript" | 
				
			|||
      src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js" | 
				
			|||
    ></script> | 
				
			|||
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script> | 
				
			|||
  <div id="App"></div> | 
				
			|||
    <script | 
				
			|||
      type="text/javascript" | 
				
			|||
      src="http://localhost:5001/client/build/app.js" | 
				
			|||
    ></script> | 
				
			|||
  <script type="text/javascript" src="http://localhost:5001/client/build/app.js"></script> | 
				
			|||
</body> | 
				
			|||
 | 
				
			|||
</html> | 
				
			|||