diff --git a/.env.development b/.env.development index de583d0940..51ce4c83f3 100644 --- a/.env.development +++ b/.env.development @@ -2,4 +2,5 @@ ENV = 'development' # base api -VUE_APP_BASE_API = '/dev-api' +#VUE_APP_BASE_API = '/api' +VUE_APP_BASE_API = 'http://127.0.0.1:8000' diff --git a/.env.production b/.env.production index 80c810301f..2bf37ad227 100644 --- a/.env.production +++ b/.env.production @@ -2,5 +2,5 @@ ENV = 'production' # base api -VUE_APP_BASE_API = '/prod-api' +VUE_APP_BASE_API = 'https://api.czzhibang.cn:8000' diff --git a/README-zh.md b/README-zh.md deleted file mode 100644 index 5b6f7bdf0e..0000000000 --- a/README-zh.md +++ /dev/null @@ -1,102 +0,0 @@ -# vue-admin-template - -> 这是一个极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。 - -[线上地址](http://panjiachen.github.io/vue-admin-template) - -[国内访问](https://panjiachen.gitee.io/vue-admin-template) - -目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。 - -## Extra - -如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control) - -## 相关项目 - -- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) - -- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) - -- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) - -- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) - -写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目: - -- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2) -- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac) -- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35) -- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板,专门针对本项目的文章,算作是一篇文档)](https://juejin.im/post/595b4d776fb9a06bbe7dba56) -- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836) - -## Build Setup - -```bash -# 克隆项目 -git clone https://github.com/PanJiaChen/vue-admin-template.git - -# 进入项目目录 -cd vue-admin-template - -# 安装依赖 -npm install - -# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 -npm install --registry=https://registry.npm.taobao.org - -# 启动服务 -npm run dev -``` - -浏览器访问 [http://localhost:9528](http://localhost:9528) - -## 发布 - -```bash -# 构建测试环境 -npm run build:stage - -# 构建生产环境 -npm run build:prod -``` - -## 其它 - -```bash -# 预览发布环境效果 -npm run preview - -# 预览发布环境效果 + 静态资源分析 -npm run preview -- --report - -# 代码格式检查 -npm run lint - -# 代码格式检查并自动修复 -npm run lint -- --fix -``` - -更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/) - -## 购买贴纸 - -你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。 - -## Demo - -![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif) - -## Browsers support - -Modern browsers and Internet Explorer 10+. - -| [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | -| --------- | --------- | --------- | --------- | -| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions - -## License - -[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license. - -Copyright (c) 2017-present PanJiaChen diff --git a/README.md b/README.md index a2f3c71543..cca820a8f5 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,45 @@ -# vue-admin-template - -English | [简体中文](./README-zh.md) - -> A minimal vue admin template with Element UI & axios & iconfont & permission control & lint - -**Live demo:** http://panjiachen.github.io/vue-admin-template - - -**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`** - -## Build Setup - -```bash -# clone the project -git clone https://github.com/PanJiaChen/vue-admin-template.git - -# enter the project directory -cd vue-admin-template - -# install dependency -npm install - -# develop -npm run dev -``` - -This will automatically open http://localhost:9528 - -## Build - -```bash -# build for test environment -npm run build:stage - -# build for production environment -npm run build:prod -``` - -## Advanced - -```bash -# preview the release environment effect -npm run preview - -# preview the release environment effect + static resource analysis -npm run preview -- --report - -# code format check -npm run lint - -# code format check and auto fix -npm run lint -- --fix -``` - -Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information - -## Demo - -![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif) - -## Extra - -If you want router permission && generate menu by user roles , you can use this branch [permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control) - -For `typescript` version, you can use [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour)) - -## Related Project - -- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) - -- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) - -- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) - -- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) - -## Browsers support - -Modern browsers and Internet Explorer 10+. - -| [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | -| --------- | --------- | --------- | --------- | -| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions - -## License - -[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license. - -Copyright (c) 2017-present PanJiaChen +三邦面料系统开发(前端) + +fork项目 vue-admin-template + +api文档: + +1. 用户模块 +1.1 登陆: (/user/login) POST +请求:{ + 'username': 用户名, + 'password': 密码 +} + +返回: +成功 { + 'code': 20000, + 'data': { + 'token': 密钥 + } +} +失败 { + 'code': 60204, + ‘message’ : '密码错误'/'没有此用户'/'登录验证错误'+error +} + + +1.2 获取用户信息 (user/info) GET +请求:params {token} + +返回: +成功 { + 'code': 20000, + 'data': { + 'data': { + 'avatar': 头像, + 'name': 姓名, + 'position': 职位, + 'roles' 权限: + } + } +} +失败 { + 'code': 50000, + ‘message’ : '登录失败,无法获取用户资料'+error +} \ No newline at end of file diff --git a/mock/index.js b/mock/index.js deleted file mode 100644 index c514c13573..0000000000 --- a/mock/index.js +++ /dev/null @@ -1,57 +0,0 @@ -const Mock = require('mockjs') -const { param2Obj } = require('./utils') - -const user = require('./user') -const table = require('./table') - -const mocks = [ - ...user, - ...table -] - -// for front mock -// please use it cautiously, it will redefine XMLHttpRequest, -// which will cause many of your third-party libraries to be invalidated(like progress event). -function mockXHR() { - // mock patch - // https://github.com/nuysoft/Mock/issues/300 - Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send - Mock.XHR.prototype.send = function() { - if (this.custom.xhr) { - this.custom.xhr.withCredentials = this.withCredentials || false - - if (this.responseType) { - this.custom.xhr.responseType = this.responseType - } - } - this.proxy_send(...arguments) - } - - function XHR2ExpressReqWrap(respond) { - return function(options) { - let result = null - if (respond instanceof Function) { - const { body, type, url } = options - // https://expressjs.com/en/4x/api.html#req - result = respond({ - method: type, - body: JSON.parse(body), - query: param2Obj(url) - }) - } else { - result = respond - } - return Mock.mock(result) - } - } - - for (const i of mocks) { - Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) - } -} - -module.exports = { - mocks, - mockXHR -} - diff --git a/mock/mock-server.js b/mock/mock-server.js deleted file mode 100644 index 8941ec0f80..0000000000 --- a/mock/mock-server.js +++ /dev/null @@ -1,81 +0,0 @@ -const chokidar = require('chokidar') -const bodyParser = require('body-parser') -const chalk = require('chalk') -const path = require('path') -const Mock = require('mockjs') - -const mockDir = path.join(process.cwd(), 'mock') - -function registerRoutes(app) { - let mockLastIndex - const { mocks } = require('./index.js') - const mocksForServer = mocks.map(route => { - return responseFake(route.url, route.type, route.response) - }) - for (const mock of mocksForServer) { - app[mock.type](mock.url, mock.response) - mockLastIndex = app._router.stack.length - } - const mockRoutesLength = Object.keys(mocksForServer).length - return { - mockRoutesLength: mockRoutesLength, - mockStartIndex: mockLastIndex - mockRoutesLength - } -} - -function unregisterRoutes() { - Object.keys(require.cache).forEach(i => { - if (i.includes(mockDir)) { - delete require.cache[require.resolve(i)] - } - }) -} - -// for mock server -const responseFake = (url, type, respond) => { - return { - url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), - type: type || 'get', - response(req, res) { - console.log('request invoke:' + req.path) - res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) - } - } -} - -module.exports = app => { - // parse app.body - // https://expressjs.com/en/4x/api.html#req.body - app.use(bodyParser.json()) - app.use(bodyParser.urlencoded({ - extended: true - })) - - const mockRoutes = registerRoutes(app) - var mockRoutesLength = mockRoutes.mockRoutesLength - var mockStartIndex = mockRoutes.mockStartIndex - - // watch files, hot reload mock server - chokidar.watch(mockDir, { - ignored: /mock-server/, - ignoreInitial: true - }).on('all', (event, path) => { - if (event === 'change' || event === 'add') { - try { - // remove mock routes stack - app._router.stack.splice(mockStartIndex, mockRoutesLength) - - // clear routes cache - unregisterRoutes() - - const mockRoutes = registerRoutes(app) - mockRoutesLength = mockRoutes.mockRoutesLength - mockStartIndex = mockRoutes.mockStartIndex - - console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) - } catch (error) { - console.log(chalk.redBright(error)) - } - } - }) -} diff --git a/mock/table.js b/mock/table.js deleted file mode 100644 index bd0e0133e1..0000000000 --- a/mock/table.js +++ /dev/null @@ -1,29 +0,0 @@ -const Mock = require('mockjs') - -const data = Mock.mock({ - 'items|30': [{ - id: '@id', - title: '@sentence(10, 20)', - 'status|1': ['published', 'draft', 'deleted'], - author: 'name', - display_time: '@datetime', - pageviews: '@integer(300, 5000)' - }] -}) - -module.exports = [ - { - url: '/vue-admin-template/table/list', - type: 'get', - response: config => { - const items = data.items - return { - code: 20000, - data: { - total: items.length, - items: items - } - } - } - } -] diff --git a/mock/user.js b/mock/user.js deleted file mode 100644 index 7555338562..0000000000 --- a/mock/user.js +++ /dev/null @@ -1,84 +0,0 @@ - -const tokens = { - admin: { - token: 'admin-token' - }, - editor: { - token: 'editor-token' - } -} - -const users = { - 'admin-token': { - roles: ['admin'], - introduction: 'I am a super administrator', - avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', - name: 'Super Admin' - }, - 'editor-token': { - roles: ['editor'], - introduction: 'I am an editor', - avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', - name: 'Normal Editor' - } -} - -module.exports = [ - // user login - { - url: '/vue-admin-template/user/login', - type: 'post', - response: config => { - const { username } = config.body - const token = tokens[username] - - // mock error - if (!token) { - return { - code: 60204, - message: 'Account and password are incorrect.' - } - } - - return { - code: 20000, - data: token - } - } - }, - - // get user info - { - url: '/vue-admin-template/user/info\.*', - type: 'get', - response: config => { - const { token } = config.query - const info = users[token] - - // mock error - if (!info) { - return { - code: 50008, - message: 'Login failed, unable to get user details.' - } - } - - return { - code: 20000, - data: info - } - } - }, - - // user logout - { - url: '/vue-admin-template/user/logout', - type: 'post', - response: _ => { - return { - code: 20000, - data: 'success' - } - } - } -] diff --git a/mock/utils.js b/mock/utils.js deleted file mode 100644 index 95cc27d5fe..0000000000 --- a/mock/utils.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @param {string} url - * @returns {Object} - */ -function param2Obj(url) { - const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') - if (!search) { - return {} - } - const obj = {} - const searchArr = search.split('&') - searchArr.forEach(v => { - const index = v.indexOf('=') - if (index !== -1) { - const name = v.substring(0, index) - const val = v.substring(index + 1, v.length) - obj[name] = val - } - }) - return obj -} - -module.exports = { - param2Obj -} diff --git a/package.json b/package.json index 24138249e2..8864b17b88 100644 --- a/package.json +++ b/package.json @@ -14,16 +14,32 @@ "test:ci": "npm run lint && npm run test:unit" }, "dependencies": { + "@algoz098/audio-recorder": "^0.1.1", "axios": "0.18.1", - "core-js": "3.6.5", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "core-js": "^3.6.5", + "crypto-js": "^4.0.0", "element-ui": "2.13.2", + "fastclick": "^1.0.6", + "inline-worker": "^1.1.0", "js-cookie": "2.2.0", + "less-loader": "^7.0.2", + "moment": "^2.29.1", "normalize.css": "7.0.0", "nprogress": "0.2.0", "path-to-regexp": "2.4.0", + "push.js": "^1.0.12", + "recorderx": "^2.0.2", + "screenfull": "^5.0.2", "vue": "2.6.10", + "vue-json-excel": "^0.3.0", + "vue-lazyload": "^1.3.3", + "vue-mobile-audio": "^0.1.3", + "vue-print-nb-z": "^1.1.6", "vue-router": "3.0.6", - "vuex": "3.1.0" + "vuex": "3.1.0", + "webpack-dev-server": "^3.11.0", + "worker-loader": "^3.0.1" }, "devDependencies": { "@vue/cli-plugin-babel": "4.4.4", @@ -31,24 +47,60 @@ "@vue/cli-plugin-unit-jest": "4.4.4", "@vue/cli-service": "4.4.4", "@vue/test-utils": "1.0.0-beta.29", - "autoprefixer": "9.5.1", + "autoprefixer": "^7.1.2", + "babel-core": "^6.22.1", "babel-eslint": "10.1.0", + "babel-helper-vue-jsx-merge-props": "^2.0.3", "babel-jest": "23.6.0", + "babel-loader": "^7.1.1", + "babel-plugin-component": "^1.1.1", "babel-plugin-dynamic-import-node": "2.3.3", + "babel-plugin-syntax-jsx": "^6.18.0", + "babel-plugin-transform-runtime": "^6.22.0", + "babel-plugin-transform-vue-jsx": "^3.5.0", + "babel-preset-env": "^1.3.2", + "babel-preset-stage-2": "^6.22.0", "chalk": "2.4.2", "connect": "3.6.6", + "copy-webpack-plugin": "^4.0.1", + "crypto-js": "^4.0.0", + "css-loader": "^0.28.0", + "enc": "^0.4.0", "eslint": "6.7.2", "eslint-plugin-vue": "6.2.2", + "extract-text-webpack-plugin": "^3.0.0", + "file-loader": "^1.1.4", + "friendly-errors-webpack-plugin": "^1.6.1", "html-webpack-plugin": "3.2.0", - "mockjs": "1.0.1-beta3", + "node-notifier": "^5.1.2", + "optimize-css-assets-webpack-plugin": "^3.2.0", + "ora": "^1.2.0", + "popper.js": "^1.16.1", + "portfinder": "^1.0.13", + "postcss-import": "^11.0.0", + "postcss-loader": "^2.0.8", + "postcss-url": "^7.2.1", + "rimraf": "^2.6.0", "runjs": "4.3.2", "sass": "1.26.8", "sass-loader": "8.0.2", "script-ext-html-webpack-plugin": "2.1.3", + "semver": "^5.3.0", "serve-static": "1.13.2", + "shelljs": "^0.7.6", + "style-loader": "^1.2.1", "svg-sprite-loader": "4.1.3", "svgo": "1.2.2", - "vue-template-compiler": "2.6.10" + "uglifyjs-webpack-plugin": "^1.1.1", + "url-loader": "^0.5.8", + "vconsole": "^3.3.4", + "vue-loader": "^15.9.3", + "vue-style-loader": "^3.0.1", + "vue-template-compiler": "2.6.10", + "webpack": "^4.44.1", + "webpack-bundle-analyzer": "^2.9.0", + "webpack-cli": "^3.3.12", + "webpack-merge": "^4.1.0" }, "browserslist": [ "> 1%", diff --git a/public/favicon.ico b/public/favicon.ico index 34b63ac63a..1175fce245 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/api/contract/contract_check.js b/src/api/contract/contract_check.js new file mode 100644 index 0000000000..8856f02350 --- /dev/null +++ b/src/api/contract/contract_check.js @@ -0,0 +1,161 @@ +import request from '@/utils/request' + +// 合同审核颜色 +export function queryContractCheckColor(data) { + return request({ + url: '/contract_check_color/query', + method: 'post', + data + }) +} + +export function addContractCheckColor(data) { + return request({ + url: '/contract_check_color/add', + method: 'post', + data + }) +} + +export function modifyContractCheckColor(data) { + return request({ + url: '/contract_check_color/modify', + method: 'post', + data + }) +} + +export function deleteContractCheckColor(data) { + return request({ + url: '/contract_check_color/delete', + method: 'post', + data + }) +} + +// 合同审核价格 +export function queryContractCheckPrice(data) { + return request({ + url: '/contract_check_price/query', + method: 'post', + data + }) +} + +export function queryContractCheckPrice_product(data) { + return request({ + url: '/contract_check_price/product', + method: 'post', + data + }) +} + +export function addContractCheckPrice(data) { + return request({ + url: '/contract_check_price/add', + method: 'post', + data + }) +} + +export function modifyContractCheckPrice(data) { + return request({ + url: '/contract_check_price/modify', + method: 'post', + data + }) +} + +export function deleteContractCheckPrice(data) { + return request({ + url: '/contract_check_price/delete', + method: 'post', + data + }) +} + +export function queryMaterialName() { + return request({ + url: '/material/query_name', + method: 'get' + }) +} + +export function queryProvider() { + return request({ + url: '/provider/query_provider', + method: 'get' + }) +} + +export function checkState(data) { + return request({ + url: '/new_contract/check_state', + method: 'post', + data + }) +} + +export function unLock(data) { + return request({ + url: '/new_contract/unlock', + method: 'post', + data + }) +} + +export function queryContractProduct(data) { + return request({ + url: '/contract_product/query', + method: 'post', + data + }) +} + +export function modifyContractProduct(data) { + return request({ + url: '/contract_product/modify', + method: 'post', + data + }) +} + +export function addContractProduct(data) { + return request({ + url: '/contract_product/add', + method: 'post', + data + }) +} + +export function deleteContractProduct(data) { + return request({ + url: '/contract_product/delete', + method: 'post', + data + }) +} + +export function submit_production(data) { + return request({ + url: '/contract_product/submit', + method: 'post', + data + }) +} + +export function export_fabric_contract(data) { + return request({ + url: '/excel/fabric_contract', + method: 'post', + data + }) +} + +export function export_cloth_contract(data) { + return request({ + url: '/excel/cloth_contract', + method: 'post', + data + }) +} diff --git a/src/api/contract/new_contract.js b/src/api/contract/new_contract.js new file mode 100644 index 0000000000..d5e40966e8 --- /dev/null +++ b/src/api/contract/new_contract.js @@ -0,0 +1,178 @@ +import request from '@/utils/request' + +export function getAllContracts(data) { + return request({ + url: '/new_contract/all', + method: 'post', + data + }) +} + +export function queryContracts(data) { + return request({ + url: '/new_contract/query', + method: 'post', + data + }) +} + +export function getContractsDetail(data) { + return request({ + url: '/new_contract/detail', + method: 'post', + data + }) +} + +export function addContracts(data) { + return request({ + url: '/new_contract/add', + method: 'post', + data + }) +} + +export function modifyContracts(data) { + return request({ + url: '/new_contract/modify', + method: 'post', + data + }) +} + +export function deleteContracts(data) { + return request({ + url: '/new_contract/delete', + method: 'post', + data + }) +} + +export function add_contract_finish(data) { + return request({ + url: '/new_contract/finish', + method: 'post', + data + }) +} + +export function querySalesman() { + return request({ + url: '/user/query_salesman', + method: 'get' + }) +} + +export function queryCustomer() { + return request({ + url: '/customer/query_company', + method: 'get' + }) +} + +export function upload(data) { + return request({ + url: '/new_contract/upload', + method: 'post', + data + }) +} + +export function query_contract_id(data) { + return request({ + url: '/contract_detail/contract_id', + method: 'post', + data + }) +} + +export function query_style_id(data) { + return request({ + url: '/contract_detail/style_id', + method: 'post', + data + }) +} + +export function query_style_name(data) { + return request({ + url: '/contract_detail/style_name', + method: 'post', + data + }) +} + +export function query_color(data) { + return request({ + url: '/contract_detail/color', + method: 'post', + data + }) +} + +export function query_name(data) { + return request({ + url: '/contract_detail/name', + method: 'post', + data + }) +} + +export function query_contract_detail(data) { + return request({ + url: '/contract_detail/query', + method: 'post', + data + }) +} + +// 合同进度 +export function add_contract_process(data) { + return request({ + url: '/contract_process/add', + method: 'post', + data + }) +} + +export function get_contract_process(data) { + return request({ + url: '/contract_process/all', + method: 'post', + data + }) +} + +export function delete_contract_process(data) { + return request({ + url: '/contract_process/delete', + method: 'post', + data + }) +} + +export function modify_contract_process(data) { + return request({ + url: '/contract_process/modify', + method: 'post', + data + }) +} + +// 翻单 +export function repeat(data) { + return request({ + url: '/new_contract/repeat', + method: 'post', + data + }) +} + +export function audio_upload(data) { + return request({ + url: '/contract_process/audio_upload', + method: 'post', + data + }) +} + diff --git a/src/api/customer.js b/src/api/customer.js new file mode 100644 index 0000000000..2861bc8357 --- /dev/null +++ b/src/api/customer.js @@ -0,0 +1,41 @@ +import request from '@/utils/request' + +export function getAllCustomers() { + return request({ + url: '/customer/all', + method: 'get' + }) +} + +export function queryCustomers(data) { + return request({ + url: '/customer/query', + method: 'post', + data + }) +} + +export function addCustomers(data) { + return request({ + url: '/customer/add', + method: 'post', + data + }) +} + +export function modifyCustomers(data) { + return request({ + url: '/customer/modify', + method: 'post', + data + }) +} + +export function deleteCustomers(data) { + return request({ + url: '/customer/delete', + method: 'post', + data + }) +} + diff --git a/src/api/finance.js b/src/api/finance.js new file mode 100644 index 0000000000..fc58e0530a --- /dev/null +++ b/src/api/finance.js @@ -0,0 +1,260 @@ +import request from '@/utils/request' +// 财务-应付款 +export function get_all_finance_provider() { + return request({ + url: '/finance_provider/all', + method: 'get' + }) +} + +export function query_finance_providers(data) { + return request({ + url: '/finance_provider/query', + method: 'post', + data + }) +} + +export function query_storage_details(data) { + return request({ + url: '/finance_provider/storage', + method: 'post', + data + }) +} + +export function query_provider_checking(data) { + return request({ + url: '/finance_provider/checking', + method: 'post', + data + }) +} + +// 财务-应收款 +export function get_all_finance_customer() { + return request({ + url: '/finance_customer/all', + method: 'get' + }) +} + +export function query_finance_customers(data) { + return request({ + url: '/finance_customer/query', + method: 'post', + data + }) +} + +export function unit_price_checked(data) { + return request({ + url: '/finance_customer/unit_price_check', + method: 'post', + data + }) +} + +export function query_storage_out_details(data) { + return request({ + url: '/finance_customer/storage', + method: 'post', + data + }) +} + +export function received_checked(data) { + return request({ + url: '/finance_customer/received_check', + method: 'post', + data + }) +} + +export function get_contract_customer_detail(data) { + return request({ + url: '/finance_customer/detail', + method: 'post', + data + }) +} + +export function query_customer_checking(data) { + return request({ + url: '/finance_customer/checking', + method: 'post', + data + }) +} + +export function get_contract_provider_detail(data) { + return request({ + url: '/finance_provider/detail', + method: 'post', + data + }) +} + +// 扣损/附加费 +export function modify_loss_fee(data) { + return request({ + url: '/finance_provider/loss_fee', + method: 'post', + data + }) +} + +export function modify_loss_fee_customer(data) { + return request({ + url: '/finance_customer/loss_fee', + method: 'post', + data + }) +} +// 付款审核 +export function payment_check(data) { + return request({ + url: '/finance_provider/check', + method: 'post', + data + }) +} + +// 付款/收款/开票 +export function query_payment_receipt(data) { + return request({ + url: '/payment_receipt/query', + method: 'post', + data + }) +} + +export function add_payment_receipt(data) { + return request({ + url: '/payment_receipt/add', + method: 'post', + data + }) +} + +export function modify_payment_receipt(data) { + return request({ + url: '/payment_receipt/modify', + method: 'post', + data + }) +} + +export function delete_payment_receipt(data) { + return request({ + url: '/payment_receipt/delete', + method: 'post', + data + }) +} +export function query_payment_receipt_overall_provider(data) { + return request({ + url: '/payment_receipt/overall', + method: 'post', + data + }) +} + +// 付款/收款/开票 +export function query_payment_receipt_customer(data) { + return request({ + url: '/payment_receipt_customer/query', + method: 'post', + data + }) +} + +export function add_payment_receipt_customer(data) { + return request({ + url: '/payment_receipt_customer/add', + method: 'post', + data + }) +} + +export function modify_payment_receipt_customer(data) { + return request({ + url: '/payment_receipt_customer/modify', + method: 'post', + data + }) +} + +export function delete_payment_receipt_customer(data) { + return request({ + url: '/payment_receipt_customer/delete', + method: 'post', + data + }) +} + +export function query_payment_receipt_overall_customer(data) { + return request({ + url: '/payment_receipt_customer/overall', + method: 'post', + data + }) +} + +// 其他费用 +export function query_otherfee(data) { + return request({ + url: '/other_fee/query', + method: 'post', + data + }) +} + +export function add_otherfee(data) { + return request({ + url: '/other_fee/add', + method: 'post', + data + }) +} + +export function modify_otherfee(data) { + return request({ + url: '/other_fee/modify', + method: 'post', + data + }) +} + +export function delete_otherfee(data) { + return request({ + url: '/other_fee/delete', + method: 'post', + data + }) +} + +// 合同核算 +export function query_accounting(data) { + return request({ + url: '/contract_accounting/query', + method: 'post', + data + }) +} + +export function other_info(data) { + return request({ + url: '/contract_accounting/other_info', + method: 'post', + data + }) +} + +export function modify_discription(data) { + return request({ + url: '/contract_accounting/modify', + method: 'post', + data + }) +} diff --git a/src/api/material.js b/src/api/material.js new file mode 100644 index 0000000000..cbccd7147a --- /dev/null +++ b/src/api/material.js @@ -0,0 +1,40 @@ +import request from '@/utils/request' + +export function getAllMaterials() { + return request({ + url: '/material/all', + method: 'get' + }) +} + +export function queryMaterials(data) { + return request({ + url: '/material/query', + method: 'post', + data + }) +} + +export function addMaterials(data) { + return request({ + url: '/material/add', + method: 'post', + data + }) +} + +export function modifyMaterials(data) { + return request({ + url: '/material/modify', + method: 'post', + data + }) +} + +export function deleteMaterials(data) { + return request({ + url: '/material/delete', + method: 'post', + data + }) +} diff --git a/src/api/provider.js b/src/api/provider.js new file mode 100644 index 0000000000..85656cbd1c --- /dev/null +++ b/src/api/provider.js @@ -0,0 +1,40 @@ +import request from '@/utils/request' + +export function getAllProviders() { + return request({ + url: '/provider/all', + method: 'get' + }) +} + +export function queryProviders(data) { + return request({ + url: '/provider/query', + method: 'post', + data + }) +} + +export function addProviders(data) { + return request({ + url: '/provider/add', + method: 'post', + data + }) +} + +export function modifyProviders(data) { + return request({ + url: '/provider/modify', + method: 'post', + data + }) +} + +export function deleteProviders(data) { + return request({ + url: '/provider/delete', + method: 'post', + data + }) +} diff --git a/src/api/storage.js b/src/api/storage.js new file mode 100644 index 0000000000..9fd597788c --- /dev/null +++ b/src/api/storage.js @@ -0,0 +1,186 @@ +import request from '@/utils/request' + +export function upload_img(data) { + return request({ + url: '/contract_storage/upload_img', + method: 'post', + data + }) +} + +export function delete_img(data) { + return request({ + url: '/contract_storage/delete_img', + method: 'post', + data + }) +} + +export function query_contract_storage_record(data) { + return request({ + url: '/contract_storage/query', + method: 'post', + data + }) +} + +export function add_contract_storage_record(data) { + return request({ + url: '/contract_storage/add', + method: 'post', + data + }) +} + +export function modify_contract_storage_record(data) { + return request({ + url: '/contract_storage/modify', + method: 'post', + data + }) +} + +export function delete_contract_storage_record(data) { + return request({ + url: '/contract_storage/delete', + method: 'post', + data + }) +} + +// 成衣出库一览 +export function query_storage_cloth(data) { + return request({ + url: '/contract_storage/cloth', + method: 'post', + data + }) +} + +export function get_storage_cloth() { + return request({ + url: '/contract_storage/cloth_all', + method: 'get' + }) +} + +// 面辅料服饰入库一览 +export function query_storage_fabric_sup(data) { + return request({ + url: '/contract_storage/fabric_sup', + method: 'post', + data + }) +} + +export function get_storage_fabric_sup() { + return request({ + url: '/contract_storage/fabric_sup_all', + method: 'get' + }) +} + +// 成衣库存 +export function get_contract_detail(data) { + return request({ + url: '/cloth_stock/contract_detail', + method: 'post', + data + }) +} + +export function get_fabric_sup_detail(data) { + return request({ + url: '/fabric_sup_stock/contract_detail', + method: 'post', + data + }) +} + +// 仓库 +export function query_warehouse(data) { + return request({ + url: '/warehouse/query', + method: 'post', + data + }) +} + +export function add_warehouse(data) { + return request({ + url: '/warehouse/add', + method: 'post', + data + }) +} + +export function modify_warehouse(data) { + return request({ + url: '/warehouse/modify', + method: 'post', + data + }) +} + +export function delete_warehouse(data) { + return request({ + url: '/warehouse/delete', + method: 'post', + data + }) +} + +export function get_warehouse_label() { + return request({ + url: '/warehouse/label', + method: 'get' + }) +} + +export function add_stock_record(data) { + return request({ + url: '/stock_record/add', + method: 'post', + data + }) +} + +export function modify_stock_record(data) { + return request({ + url: '/stock_record/modify', + method: 'post', + data + }) +} + +export function delete_stock_record(data) { + return request({ + url: '/stock_record/delete', + method: 'post', + data + }) +} + +export function delete_stock_record_overall(data) { + return request({ + url: '/stock_record_overall/delete', + method: 'post', + data + }) +} + +export function query_stock_record_overall(data) { + return request({ + url: '/stock_record_overall/query', + method: 'post', + data + }) +} + +export function query_stock_records(data) { + return request({ + url: '/stock_record/query', + method: 'post', + data + }) +} diff --git a/src/api/user.js b/src/api/user.js index 8ff4389dba..63fd9c2ca7 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -2,7 +2,7 @@ import request from '@/utils/request' export function login(data) { return request({ - url: '/vue-admin-template/user/login', + url: '/user/login', method: 'post', data }) @@ -10,7 +10,7 @@ export function login(data) { export function getInfo(token) { return request({ - url: '/vue-admin-template/user/info', + url: '/user/info', method: 'get', params: { token } }) @@ -18,7 +18,132 @@ export function getInfo(token) { export function logout() { return request({ - url: '/vue-admin-template/user/logout', + url: '/user/logout', method: 'post' }) } + +export function ActiveRouter(token) { + return request({ + url: '/group/subMenu', + method: 'get', + params: { token } + }) +} + +export function getAllUsers() { + return request({ + url: '/user/all', + method: 'get' + }) +} + +export function queryUsers(data) { + return request({ + url: '/user/query', + method: 'post', + data + }) +} + +export function addUsers(data) { + return request({ + url: '/user/add', + method: 'post', + data + }) +} + +export function modifyUsers(data) { + return request({ + url: '/user/modify', + method: 'post', + data + }) +} + +export function deleteUsers(data) { + return request({ + url: '/user/delete', + method: 'post', + data + }) +} + +// export function getUserRole(data) { +// return request({ +// url: '/user/query_role', +// method: 'post', +// data +// }) +// } + +// 用户组 +export function getAllGroups() { + return request({ + url: '/group/all', + method: 'get' + }) +} + +export function modifyGroupUser() { + return request({ + url: '/group/modifyUser', + method: 'post' + }) +} + +export function upload(data) { + return request({ + url: '/user/upload', + method: 'post', + data + }) +} + +export function modifypasswd(data) { + return request({ + url: '/user/modifypasswd', + method: 'post', + data + }) +} + +export function query_msg(data) { + return request({ + url: '/user/msg', + method: 'post', + data + }) +} + +export function clear_msg(data) { + return request({ + url: '/user/clear_msg', + method: 'post', + data + }) +} + +// 查询错误 +export function error_query() { + return request({ + url: '/error/query', + method: 'get' + }) +} + +export function error_delete() { + return request({ + url: '/error/delete', + method: 'get' + }) +} + +// 获取业务员 +export function query_salesman() { + return request({ + url: '/user/query_salesman', + method: 'get' + }) +} diff --git a/src/assets/ic_record.gif b/src/assets/ic_record.gif new file mode 100644 index 0000000000..fe67dad549 Binary files /dev/null and b/src/assets/ic_record.gif differ diff --git a/src/assets/ic_release_to_cancel.png b/src/assets/ic_release_to_cancel.png new file mode 100644 index 0000000000..de9672cc3d Binary files /dev/null and b/src/assets/ic_release_to_cancel.png differ diff --git a/src/assets/timg.gif b/src/assets/timg.gif new file mode 100644 index 0000000000..c837bff694 Binary files /dev/null and b/src/assets/timg.gif differ diff --git a/src/components/IatRecorder/index.js b/src/components/IatRecorder/index.js new file mode 100644 index 0000000000..988857404a --- /dev/null +++ b/src/components/IatRecorder/index.js @@ -0,0 +1,541 @@ +/** + * Created by lycheng on 2019/8/1. + * + * 语音听写流式 WebAPI 接口调用示例 接口文档(必看):https://doc.xfyun.cn/rest_api/语音听写(流式版).html + * webapi 听写服务参考帖子(必看):http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=38947&extra= + * 语音听写流式WebAPI 服务,热词使用方式:登陆开放平台https://www.xfyun.cn/后,找到控制台--我的应用---语音听写---个性化热词,上传热词 + * 注意:热词只能在识别的时候会增加热词的识别权重,需要注意的是增加相应词条的识别率,但并不是绝对的,具体效果以您测试为准。 + * 错误码链接: + * https://www.xfyun.cn/doc/asr/voicedictation/API.html#%E9%94%99%E8%AF%AF%E7%A0%81 + * https://www.xfyun.cn/document/error-code (code返回错误码时必看) + * 语音听写流式WebAPI 服务,方言或小语种试用方法:登陆开放平台https://www.xfyun.cn/后,在控制台--语音听写(流式)--方言/语种处添加 + * 添加后会显示该方言/语种的参数值 + * + */ + +// 1. websocket连接:判断浏览器是否兼容,获取websocket url并连接,这里为了方便本地生成websocket url +// 2. 获取浏览器录音权限:判断浏览器是否兼容,获取浏览器录音权限, +// 3. js获取浏览器录音数据 +// 4. 将录音数据处理为文档要求的数据格式:采样率16k或8K、位长16bit、单声道;该操作属于纯数据处理,使用webWork处理 +// 5. 根据要求(采用base64编码,每次发送音频间隔40ms,每次发送音频字节数1280B)将处理后的数据通过websocket传给服务器, +// 6. 实时接收websocket返回的数据并进行处理 + +// ps: 该示例用到了es6中的一些语法,建议在chrome下运行 + +import CryptoJS from 'crypto-js' +import TransWorker from './transcode2.worker.js' +// import './index.css' +// import {getAuthUrl} from '@/api/websocketUrl.js' + +// const transWorker = new Worker('./transcode2.worker.js') +const transWorker = new TransWorker() +// console.log(transWorker) +// APPID,APISecret,APIKey在控制台-我的应用-语音听写(流式版)页面获取 +const APPID = '5fc43f4e' +const API_SECRET = '36bed5c0abb02f5b27a5331188f3af08' +const API_KEY = 'b46fa3a731604783f3dc141b4e63628c' +var startTime = '' +var endTime = '' + +/** + * 获取websocket url + * 该接口需要后端提供,这里为了方便前端处理 + */ +function getWebSocketUrl() { + return new Promise((resolve, reject) => { + // 请求地址根据语种不同变化 + var url = 'wss://iat-api.xfyun.cn/v2/iat' + var host = 'iat-api.xfyun.cn' + var apiKey = API_KEY + var apiSecret = API_SECRET + var date = new Date().toGMTString() + var algorithm = 'hmac-sha256' + var headers = 'host date request-line' + var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1` + var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret) + var signature = CryptoJS.enc.Base64.stringify(signatureSha) + var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"` + var authorization = btoa(authorizationOrigin) + url = `${url}?authorization=${authorization}&date=${date}&host=${host}` + resolve(url) + }) +} + +class IatRecorder { + constructor({ language, accent, appId } = {}) { + const self = this + this.status = 'null' + this.language = language || 'zh_cn' + this.accent = accent || 'mandarin' + this.appId = appId || APPID + // 记录音频数据 + this.audioData = [] + // 记录听写结果 + this.resultText = '' + // 保存录音 + this.leftDataList = [] + this.rightDataList = [] + // 保存录音 end + // wpgs下的听写结果需要中间状态辅助记录 + + this.resultTextTemp = '' + this.stream_track = null + transWorker.onmessage = function(event) { + // console.log('构造方法中', self.audioData) + self.audioData.push(...event.data) + } + } + // 修改录音听写状态 + setStatus(status) { + this.onWillStatusChange && this.status !== status && this.onWillStatusChange(this.status, status) + this.status = status + } + setResultText({ resultText, resultTextTemp } = {}) { + // console.log(resultText + '-----' + resultTextTemp) + this.onTextChange && this.onTextChange(resultTextTemp || resultText || '') + resultText !== undefined && (this.resultText = resultText) + resultTextTemp !== undefined && (this.resultTextTemp = resultTextTemp) + } + // 修改听写参数 + setParams({ language, accent } = {}) { + language && (this.language = language) + accent && (this.accent = accent) + } + // 连接websocket + connectWebSocket() { + return getWebSocketUrl().then(url => { + let iatWS + if ('WebSocket' in window) { + iatWS = new WebSocket(url) + } else { + alert('浏览器不支持WebSocket') + return + } + this.webSocket = iatWS + this.setStatus('init') + iatWS.onopen = e => { + this.setStatus('ing') + // 重新开始录音 + setTimeout(() => { + this.webSocketSend() + }, 500) + } + iatWS.onmessage = e => { + this.result(e.data) + } + iatWS.onerror = e => { + this.recorderStop() + } + iatWS.onclose = e => { + endTime = Date.parse(new Date()) + console.log('持续时间', endTime - startTime) + this.recorderStop() + } + }) + } + getUserMedia(constrains) { + if (navigator.mediaDevices.getUserMedia) { + // 最新标准API + navigator.mediaDevices.getUserMedia(constrains).then(stream => { this.getMediaSuccess(stream) }).catch(err => { this.getMediaFail(err) }) + } else if (navigator.webkitGetUserMedia) { + // webkit内核浏览器 + navigator.webkitGetUserMedia(constrains).then(stream => { this.getMediaSuccess(stream) }).catch(err => { this.getMediaFail(err) }) + } else if (navigator.mozGetUserMedia) { + // Firefox浏览器 + navigator.mozGetUserMedia(constrains).then(stream => { this.getMediaSuccess(stream) }).catch(err => { this.getMediaFail(err) }) + } else if (navigator.getUserMedia) { + // 旧版API + navigator.getUserMedia(constrains).then(stream => { this.getMediaSuccess(stream) }).catch(err => { this.getMediaFail(err) }) + } else { + if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) { + alert('chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限') + } else { + alert('无法获取浏览器录音功能,请升级浏览器或使用chrome') + } + this.audioContext && this.audioContext.close() + return + } + } + // 初始化浏览器录音 + recorderInit() { + navigator.getUserMedia = + navigator.getUserMedia || + navigator.webkitGetUserMedia || + navigator.mozGetUserMedia || + navigator.msGetUserMedia + + // 创建音频环境 + try { + this.audioContext = new (window.AudioContext || window.webkitAudioContext)() + this.audioContext.resume() + if (!this.audioContext) { + alert('浏览器不支持webAudioApi相关接口') + return + } + } catch (e) { + if (!this.audioContext) { + alert('浏览器不支持webAudioApi相关接口') + return + } + } + // console.log(navigator, navigator.mediaDevices) + // 获取浏览器录音权限 + + // if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + // // console.log(navigator) + // navigator.mediaDevices + // .getUserMedia({ + // audio: true, + // video: false + // }) + // .then(stream => { + // // console.log(stream) + // getMediaSuccess(stream) + // }) + // .catch(e => { + // getMediaFail(e) + // }) + // } else if (navigator.getUserMedia) { + // navigator.getUserMedia( + // { + // audio: true, + // video: false + // }, + // stream => { + // getMediaSuccess(stream) + // }, + // function(e) { + // getMediaFail(e) + // } + // ) + // } else { + // if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) { + // alert('chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限') + // } else { + // alert('无法获取浏览器录音功能,请升级浏览器或使用chrome') + // } + // this.audioContext && this.audioContext.close() + // return + // } + const constrains = { audio: true } + if (navigator.mediaDevices.getUserMedia) { + // 最新标准API + navigator.mediaDevices.getUserMedia(constrains).then(stream => { getMediaSuccess(stream) }).catch(err => { getMediaFail(err) }) + } else if (navigator.webkitGetUserMedia) { + // webkit内核浏览器 + navigator.webkitGetUserMedia(constrains).then(stream => { getMediaSuccess(stream) }).catch(err => { getMediaFail(err) }) + } else if (navigator.mozGetUserMedia) { + // Firefox浏览器 + navigator.mozGetUserMedia(constrains).then(stream => { getMediaSuccess(stream) }).catch(err => { getMediaFail(err) }) + } else if (navigator.getUserMedia) { + // 旧版API + navigator.getUserMedia(constrains).then(stream => { getMediaSuccess(stream) }).catch(err => { getMediaFail(err) }) + } else { + if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) { + alert('chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限') + } else { + alert('无法获取浏览器录音功能,请升级浏览器或使用chrome') + } + this.audioContext && this.audioContext.close() + return + } + var that = this + // 获取浏览器录音权限成功的回调 + const getMediaSuccess = stream => { + // console.log('getMediaSuccess') + // 创建一个用于通过JavaScript直接处理音频 + // 新增保存录音 + + // 新增保存录音end + this.scriptProcessor = this.audioContext.createScriptProcessor(4096, 2, 2) + // 保存录音 + + // 保存录音 end + this.scriptProcessor.onaudioprocess = e => { + // 去处理音频数据 + if (this.status === 'ing') { + // debugger + transWorker.postMessage(e.inputBuffer.getChannelData(0)) + // 保存录音 + + const leftChannelData = e.inputBuffer.getChannelData(0) + const rightChannelData = e.inputBuffer.getChannelData(1) + // 需要克隆一下 + that.leftDataList.push(leftChannelData.slice(0)) + that.rightDataList.push(rightChannelData.slice(0)) + + // 保存录音 end + } + } + // 创建一个新的MediaStreamAudioSourceNode 对象,使来自MediaStream的音频可以被播放和操作 + this.mediaSource = this.audioContext.createMediaStreamSource(stream) + // 连接 + this.stream_track = stream.getTracks()[0] + this.mediaSource.connect(this.scriptProcessor) + this.scriptProcessor.connect(this.audioContext.destination) + this.connectWebSocket() + } + + const getMediaFail = (e) => { + alert('请求麦克风失败') + console.log(e) + this.audioContext && this.audioContext.close() + this.audioContext = undefined + // 关闭websocket + if (this.webSocket && this.webSocket.readyState === 1) { + this.webSocket.close() + } + } + } + recorderStart() { + if (!this.audioContext) { + this.recorderInit() + console.log('录音初始化') + } else { + this.audioContext.resume() + console.log('继续录音') + this.connectWebSocket() + } + } + // 暂停录音 + recorderStop() { + // safari下suspend后再次resume录音内容将是空白,设置safari下不做suspend + if (!(/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgen))) { + this.audioContext && this.audioContext.suspend() + } + // console.log('audioContext', this.audioContext) + this.setStatus('end') + // this.stream_track.stop() + // 发送语音并保存点击播放 + if (this.leftDataList.length !== 0) { + this.stopRecord(this.leftDataList, this.rightDataList) + } + return this.stream_track + } + // + mergeArray(list) { + const length = list.length * list[0].length + const data = new Float32Array(length) + let offset = 0 + for (let i = 0; i < list.length; i++) { + data.set(list[i], offset) + offset += list[i].length + } + return data + } + stopRecord(leftDataList, rightDataList) { + // 停止录音 + const leftData = this.mergeArray(leftDataList) + const rightData = this.mergeArray(rightDataList) + const audioData = this.interleaveLeftAndRight(leftData, rightData) + const wavBuffer = this.createWavFile(audioData) + this.playRecord(wavBuffer) + } + interleaveLeftAndRight(left, right) { + const totalLength = left.length + right.length + const data = new Float32Array(totalLength) + for (let i = 0; i < left.length; i++) { + const k = i * 2 + data[k] = left[i] + data[k + 1] = right[i] + } + return data + } + createWavFile(audioData) { + // console.log(this.audioData, this.audioContext) + const WAV_HEAD_SIZE = 44 + const buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE) + // 需要用一个view来操控buffer + const view = new DataView(buffer) + // 写入wav头部信息 + // RIFF chunk descriptor/identifier + this.writeUTFBytes(view, 0, 'RIFF') + // RIFF chunk length + view.setUint32(4, 44 + audioData.length * 2, true) + // RIFF type + this.writeUTFBytes(view, 8, 'WAVE') + // format chunk identifier + // FMT sub-chunk + this.writeUTFBytes(view, 12, 'fmt ') + // format chunk length + view.setUint32(16, 16, true) + // sample format (raw) + view.setUint16(20, 1, true) + // stereo (2 channels) + view.setUint16(22, 2, true) + // sample rate + view.setUint32(24, 48000, true) + // byte rate (sample rate * block align) + view.setUint32(28, 48000 * 2, true) + // block align (channel count * bytes per sample) + view.setUint16(32, 2 * 2, true) + // bits per sample + view.setUint16(34, 16, true) + // data sub-chunk + // data chunk identifier + this.writeUTFBytes(view, 36, 'data') + // data chunk length + view.setUint32(40, audioData.length * 2, true) + // 写入PCM数据 + const length = audioData.length + let index = 44 + const volume = 1 + for (let i = 0; i < length; i++) { + view.setInt16(index, audioData[i] * (0x7FFF * volume), true) + index += 2 + } + return buffer + } + writeUTFBytes(view, offset, string) { + var lng = string.length + for (var i = 0; i < lng; i++) { + view.setUint8(offset + i, string.charCodeAt(i)) + } + } + playRecord(arrayBuffer) { + const blob = new Blob([new Uint8Array(arrayBuffer)], { type: 'audio/wav' }) + // console.log(blob) + const blobUrl = URL.createObjectURL(blob) + localStorage.setItem('audioURLnew', blobUrl) + console.log('保存成功') + this.leftDataList = [] + this.rightDataList = [] + } + // 处理音频数据 + // transAudioData(audioData) { + // audioData = transAudioData.transaction(audioData) + // this.audioData.push(...audioData) + // } + // 对处理后的音频数据进行base64编码, + toBase64(buffer) { + var binary = '' + var bytes = new Uint8Array(buffer) + var len = bytes.byteLength + for (var i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]) + } + return window.btoa(binary) + } + // 向webSocket发送数据 + webSocketSend() { + if (this.webSocket.readyState !== 1) { + return + } + let audioData = this.audioData.splice(0, 1280) + var params = { + common: { + app_id: this.appId + }, + business: { + language: this.language, // 小语种可在控制台--语音听写(流式)--方言/语种处添加试用 + domain: 'iat', + accent: this.accent, // 中文方言可在控制台--语音听写(流式)--方言/语种处添加试用 + vad_eos: 5000, + dwa: 'wpgs' // 为使该功能生效,需到控制台开通动态修正功能(该功能免费) + }, + data: { + status: 0, + format: 'audio/L16;rate=16000', + encoding: 'raw', + audio: this.toBase64(audioData) + } + } + console.log('参数language:', this.language) + console.log('参数accent:', this.accent) + startTime = Date.parse(new Date()) + this.webSocket.send(JSON.stringify(params)) + this.handlerInterval = setInterval(() => { + // websocket未连接 + if (this.webSocket.readyState !== 1) { + console.log('websocket未连接') + this.audioData = [] + clearInterval(this.handlerInterval) + return + } + if (this.audioData.length === 0) { + console.log('自动关闭', this.status) + if (this.status === 'end') { + this.webSocket.send( + JSON.stringify({ + data: { + status: 2, + format: 'audio/L16;rate=16000', + encoding: 'raw', + audio: '' + } + }) + ) + this.audioData = [] + clearInterval(this.handlerInterval) + } + return false + } + audioData = this.audioData.splice(0, 1280) + // 中间帧 + // localStorage.setItem('voiceFun', 'on') + this.webSocket.send( + JSON.stringify({ + data: { + status: 1, + format: 'audio/L16;rate=16000', + encoding: 'raw', + audio: this.toBase64(audioData) + } + }) + ) + }, 40) + } + result(resultData) { + // 识别结束 + // localStorage.setItem('voiceFun', 'on') + const jsonData = JSON.parse(resultData) + if (jsonData.data && jsonData.data.result) { + const data = jsonData.data.result + let str = '' + // const resultStr = '' + const ws = data.ws + for (let i = 0; i < ws.length; i++) { + str = str + ws[i].cw[0].w + } + console.log('识别的结果为:', str) + // 开启wpgs会有此字段(前提:在控制台开通动态修正功能) + // 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段 + if (data.pgs) { + if (data.pgs === 'apd') { + // 将resultTextTemp同步给resultText + this.setResultText({ + resultText: this.resultTextTemp + }) + } + // 将结果存储在resultTextTemp中 + this.setResultText({ + resultTextTemp: this.resultText + str + }) + } else { + this.setResultText({ + resultText: this.resultText + str + }) + } + } + if (jsonData.code === 0 && jsonData.data.status === 2) { + this.webSocket.close() + localStorage.setItem('voiceFun', 'off') + } + if (jsonData.code !== 0) { + this.webSocket.close() + localStorage.setItem('voiceFun', 'off') + } + } + start() { + localStorage.setItem('voiceFun', 'on') + this.recorderStart() + this.setResultText({ resultText: '', resultTextTemp: '' }) + } + stop() { + return this.recorderStop() + } +} + +export { + IatRecorder +} diff --git a/src/components/IatRecorder/transcode.worker.js b/src/components/IatRecorder/transcode.worker.js new file mode 100644 index 0000000000..88cf7de3cb --- /dev/null +++ b/src/components/IatRecorder/transcode.worker.js @@ -0,0 +1,47 @@ +/* + * @Autor: lycheng + * @Date: 2020-01-07 08:51:50 + */ + +(function() { + self.onmessage = function(e) { + transAudioData.transcode(e.data) + } + + const transAudioData = { + transcode(audioData) { + let output = transAudioData.to16kHz(audioData) + output = transAudioData.to16BitPCM(output) + output = Array.from(new Uint8Array(output.buffer)) + self.postMessage(output) + // return output + }, + to16kHz(audioData) { + var data = new Float32Array(audioData) + var fitCount = Math.round(data.length * (16000 / 44100)) + var newData = new Float32Array(fitCount) + var springFactor = (data.length - 1) / (fitCount - 1) + newData[0] = data[0] + for (let i = 1; i < fitCount - 1; i++) { + var tmp = i * springFactor + var before = Math.floor(tmp).toFixed() + var after = Math.ceil(tmp).toFixed() + var atPoint = tmp - before + newData[i] = data[before] + (data[after] - data[before]) * atPoint + } + newData[fitCount - 1] = data[data.length - 1] + return newData + }, + to16BitPCM(input) { + var dataLength = input.length * (16 / 8) + var dataBuffer = new ArrayBuffer(dataLength) + var dataView = new DataView(dataBuffer) + var offset = 0 + for (var i = 0; i < input.length; i++, offset += 2) { + var s = Math.max(-1, Math.min(1, input[i])) + dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true) + } + return dataView + } + } +})() diff --git a/src/components/IatRecorder/transcode2.worker.js b/src/components/IatRecorder/transcode2.worker.js new file mode 100644 index 0000000000..3b25c04a24 --- /dev/null +++ b/src/components/IatRecorder/transcode2.worker.js @@ -0,0 +1,40 @@ + +self.onmessage = function(e) { + transAudioData.transcode(e.data) +} +const transAudioData = { + transcode(audioData) { + let output = transAudioData.to16kHz(audioData) + output = transAudioData.to16BitPCM(output) + output = Array.from(new Uint8Array(output.buffer)) + self.postMessage(output) + // return output + }, + to16kHz(audioData) { + var data = new Float32Array(audioData) + var fitCount = Math.round(data.length * (16000 / 44100)) + var newData = new Float32Array(fitCount) + var springFactor = (data.length - 1) / (fitCount - 1) + newData[0] = data[0] + for (let i = 1; i < fitCount - 1; i++) { + var tmp = i * springFactor + var before = Math.floor(tmp).toFixed() + var after = Math.ceil(tmp).toFixed() + var atPoint = tmp - before + newData[i] = data[before] + (data[after] - data[before]) * atPoint + } + newData[fitCount - 1] = data[data.length - 1] + return newData + }, + to16BitPCM(input) { + var dataLength = input.length * (16 / 8) + var dataBuffer = new ArrayBuffer(dataLength) + var dataView = new DataView(dataBuffer) + var offset = 0 + for (var i = 0; i < input.length; i++, offset += 2) { + var s = Math.max(-1, Math.min(1, input[i])) + dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true) + } + return dataView + } +} diff --git a/src/components/Screenfull/index.vue b/src/components/Screenfull/index.vue new file mode 100644 index 0000000000..c898b65c33 --- /dev/null +++ b/src/components/Screenfull/index.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/directives/el-drag-dialog/drag.js b/src/directives/el-drag-dialog/drag.js new file mode 100644 index 0000000000..299e985440 --- /dev/null +++ b/src/directives/el-drag-dialog/drag.js @@ -0,0 +1,77 @@ +export default { + bind(el, binding, vnode) { + const dialogHeaderEl = el.querySelector('.el-dialog__header') + const dragDom = el.querySelector('.el-dialog') + dialogHeaderEl.style.cssText += ';cursor:move;' + dragDom.style.cssText += ';top:0px;' + + // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); + const getStyle = (function() { + if (window.document.currentStyle) { + return (dom, attr) => dom.currentStyle[attr] + } else { + return (dom, attr) => getComputedStyle(dom, false)[attr] + } + })() + + dialogHeaderEl.onmousedown = (e) => { + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = e.clientX - dialogHeaderEl.offsetLeft + const disY = e.clientY - dialogHeaderEl.offsetTop + + const dragDomWidth = dragDom.offsetWidth + const dragDomHeight = dragDom.offsetHeight + + const screenWidth = document.body.clientWidth + const screenHeight = document.body.clientHeight + + const minDragDomLeft = dragDom.offsetLeft + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth + + const minDragDomTop = dragDom.offsetTop + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight + + // 获取到的值带px 正则匹配替换 + let styL = getStyle(dragDom, 'left') + let styT = getStyle(dragDom, 'top') + + if (styL.includes('%')) { + styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100) + styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100) + } else { + styL = +styL.replace(/\px/g, '') + styT = +styT.replace(/\px/g, '') + } + + document.onmousemove = function(e) { + // 通过事件委托,计算移动的距离 + let left = e.clientX - disX + let top = e.clientY - disY + + // 边界处理 + if (-(left) > minDragDomLeft) { + left = -minDragDomLeft + } else if (left > maxDragDomLeft) { + left = maxDragDomLeft + } + + if (-(top) > minDragDomTop) { + top = -minDragDomTop + } else if (top > maxDragDomTop) { + top = maxDragDomTop + } + + // 移动当前元素 + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;` + + // emit onDrag event + vnode.child.$emit('dragDialog') + } + + document.onmouseup = function(e) { + document.onmousemove = null + document.onmouseup = null + } + } + } +} diff --git a/src/directives/el-drag-dialog/index.js b/src/directives/el-drag-dialog/index.js new file mode 100644 index 0000000000..29facbfb3e --- /dev/null +++ b/src/directives/el-drag-dialog/index.js @@ -0,0 +1,13 @@ +import drag from './drag' + +const install = function(Vue) { + Vue.directive('el-drag-dialog', drag) +} + +if (window.Vue) { + window['el-drag-dialog'] = drag + Vue.use(install); // eslint-disable-line +} + +drag.install = install +export default drag diff --git a/src/icons/svg/exit-fullscreen.svg b/src/icons/svg/exit-fullscreen.svg new file mode 100644 index 0000000000..485c128b61 --- /dev/null +++ b/src/icons/svg/exit-fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/finance.svg b/src/icons/svg/finance.svg new file mode 100644 index 0000000000..d15a77236c --- /dev/null +++ b/src/icons/svg/finance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/finance_in.svg b/src/icons/svg/finance_in.svg new file mode 100644 index 0000000000..eddeaea529 --- /dev/null +++ b/src/icons/svg/finance_in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/finance_out.svg b/src/icons/svg/finance_out.svg new file mode 100644 index 0000000000..58a78f7a5d --- /dev/null +++ b/src/icons/svg/finance_out.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/fullscreen.svg b/src/icons/svg/fullscreen.svg new file mode 100644 index 0000000000..0e86b6fa80 --- /dev/null +++ b/src/icons/svg/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/material.svg b/src/icons/svg/material.svg new file mode 100644 index 0000000000..c84b8d07fa --- /dev/null +++ b/src/icons/svg/material.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/provider.svg b/src/icons/svg/provider.svg new file mode 100644 index 0000000000..b62538ba97 --- /dev/null +++ b/src/icons/svg/provider.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/storage.svg b/src/icons/svg/storage.svg new file mode 100644 index 0000000000..527b5a2c13 --- /dev/null +++ b/src/icons/svg/storage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue index f6a3286f58..b3a8011b6f 100644 --- a/src/layout/components/AppMain.vue +++ b/src/layout/components/AppMain.vue @@ -1,7 +1,15 @@ @@ -10,23 +18,42 @@ export default { name: 'AppMain', computed: { + // 增加tagviews + cachedViews() { + return this.$store.state.tagsView.cachedViews + }, key() { return this.$route.path } } + // mounted() { + // console.log(this.cachedViews) + // } } - diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 0ca5cf6a09..961884bc97 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -1,29 +1,40 @@ + + diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue index 33e5ab6ecf..8cc887e586 100644 --- a/src/views/dashboard/index.vue +++ b/src/views/dashboard/index.vue @@ -1,18 +1,26 @@ diff --git a/src/views/emptyPage.vue b/src/views/emptyPage.vue new file mode 100644 index 0000000000..d385004200 --- /dev/null +++ b/src/views/emptyPage.vue @@ -0,0 +1,18 @@ + + + + diff --git a/src/views/error.vue b/src/views/error.vue new file mode 100644 index 0000000000..850532dc76 --- /dev/null +++ b/src/views/error.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/src/views/form/index.vue b/src/views/form/index.vue deleted file mode 100644 index f4d66d3bdb..0000000000 --- a/src/views/form/index.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 1db246453d..127aca3e36 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -1,9 +1,9 @@ + + diff --git a/src/views/table/index.vue b/src/views/table/index.vue deleted file mode 100644 index a1ed847f95..0000000000 --- a/src/views/table/index.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/src/views/tree/index.vue b/src/views/tree/index.vue deleted file mode 100644 index 89c6b01de2..0000000000 --- a/src/views/tree/index.vue +++ /dev/null @@ -1,78 +0,0 @@ - - - - diff --git a/src/views/users/index.vue b/src/views/users/index.vue new file mode 100644 index 0000000000..18796f9078 --- /dev/null +++ b/src/views/users/index.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/src/views/users/my.vue b/src/views/users/my.vue new file mode 100644 index 0000000000..ca9b81d745 --- /dev/null +++ b/src/views/users/my.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/views/warehouse/index.vue b/src/views/warehouse/index.vue new file mode 100644 index 0000000000..79878b2769 --- /dev/null +++ b/src/views/warehouse/index.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/vue.config.js b/vue.config.js index 4856ed02a7..44d671742e 100644 --- a/vue.config.js +++ b/vue.config.js @@ -6,7 +6,7 @@ function resolve(dir) { return path.join(__dirname, dir) } -const name = defaultSettings.title || 'vue Admin Template' // page title +const name = defaultSettings.title || '常州致邦服饰有限公司管理系统' // page title // If your port is set to 80, // use administrator privileges to execute the command line. @@ -36,19 +36,57 @@ module.exports = { warnings: false, errors: true }, - before: require('./mock/mock-server.js') + proxy: { + // 配置跨域 + '/api': { + target: 'http://119.45.238.82:8000', + // ws: true, + changeOrigin: true, + pathRewrite: { + '^/api': '' + } + }, + '/prop-api': { + target: 'http://119.45.238.82:8000', + // ws: true, + changeOrigin: true, + pathRewrite: { + '^/prop-api': '' + } + } + } + // before: require('./mock/mock-server.js') }, configureWebpack: { // provide the app's title in webpack's name field, so that // it can be accessed in index.html to inject the correct title. name: name, + // config.name = name resolve: { alias: { '@': resolve('src') } } + // config.resolve.alias = { '@': resolve('src') } + // config.module.rules.push({ + // test: /\.worker.js$/, + // use: { + // loader: 'worker-loader', + // options: { inline: true, name: 'workerName.[hash].js' } + // // options: { inline: true } + // } + // }) }, + parallel: false, chainWebpack(config) { + config.module + .rule('worker') + .test(/\.worker\.js$/) + .use('worker') + .loader('worker-loader') + .options({ + inline: 'fallback' + }) // it can improve the speed of the first screen, it is recommended to turn on preload config.plugin('preload').tap(() => [ { @@ -62,7 +100,7 @@ module.exports = { // when there are many pages, it will cause too many meaningless requests config.plugins.delete('prefetch') - + config.output.globalObject('this') // set svg-sprite-loader config.module .rule('svg') @@ -87,7 +125,7 @@ module.exports = { .plugin('ScriptExtHtmlWebpackPlugin') .after('html') .use('script-ext-html-webpack-plugin', [{ - // `runtime` must same as runtimeChunk name. default is `runtime` + // `runtime` must same as runtimeChunk name. default is `runtime` inline: /runtime\..*\.js$/ }]) .end()