Commit bf578c4d authored by 水落(YangLei)'s avatar 水落(YangLei)

Merge branch 'master' into feature/shuiluo

parents 84ece510 ef0a062a
{ {
"name": "vue-antd-admin", "name": "vue-antd-admin",
"version": "0.7.2", "version": "0.7.2",
"homepage": "https://iczer.github.io/vue-antd-admin", "homepage": "https://iczer.github.io/vue-antd-admin",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "vue-cli-service serve", "start": "vue-cli-service serve",
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
"predeploy": "yarn build", "predeploy": "yarn build",
"deploy": "gh-pages -d dist -b pages -r https://gitee.com/iczer/vue-antd-admin.git", "deploy": "gh-pages -d dist -b pages -r https://gitee.com/iczer/vue-antd-admin.git",
"docs:dev": "vuepress dev docs", "docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs", "docs:build": "vuepress build docs",
"docs:deploy": "vuepress build docs && gh-pages -d docs/.vuepress/dist -b master -r https://gitee.com/iczer/vue-antd-admin-docs.git" "docs:deploy": "vuepress build docs && gh-pages -d docs/.vuepress/dist -b master -r https://gitee.com/iczer/vue-antd-admin-docs.git"
},
"dependencies": {
"@antv/data-set": "^0.11.4",
"@tailwindcss/postcss7-compat": "^2.2.2",
"cronstrue": "^1.106.0",
"animate.css": "^4.1.0",
"ant-design-vue": "1.7.2",
"axios": "^0.21.1",
"clipboard": "^2.0.6",
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"date-fns": "^2.14.0",
"highlight.js": "^10.2.1",
"lodash": "^4.17.21",
"mockjs": "^1.1.0",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"regenerator-runtime": "^0.13.7",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.2",
"viser-vue": "^2.4.8",
"vue": "^2.6.11",
"vue-i18n": "^8.18.2",
"vue-router": "^3.3.4",
"vuedraggable": "^2.23.2",
"vuex": "^3.4.0"
},
"devDependencies": {
"@ant-design/colors": "^4.0.1",
"@babel/eslint-parser": "^7.14.7",
"@vue/cli-plugin-babel": "^4.4.0",
"@vue/cli-plugin-eslint": "^4.4.0",
"@vue/cli-service": "^4.4.0",
"@vuepress/plugin-back-to-top": "^1.5.2",
"autoprefixer": "^9.8.6",
"babel-plugin-transform-remove-console": "^6.9.4",
"babel-polyfill": "^6.26.0",
"compression-webpack-plugin": "^2.0.0",
"deepmerge": "^4.2.2",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-vue": "^6.2.2",
"fast-deep-equal": "^3.1.3",
"gh-pages": "^3.1.0",
"less-loader": "^6.1.1",
"style-resources-loader": "^1.3.2",
"vue-cli-plugin-style-resources-loader": "^0.1.4",
"vue-template-compiler": "^2.6.11",
"vuepress": "^1.5.2",
"webpack-theme-color-replacer": "^1.3.12",
"whatwg-fetch": "^3.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
}, },
"dependencies": { "extends": [
"@antv/data-set": "^0.11.4", "plugin:vue/essential",
"@tailwindcss/postcss7-compat": "^2.2.2", "eslint:recommended"
"animate.css": "^4.1.0",
"ant-design-vue": "1.7.2",
"axios": "^0.21.1",
"clipboard": "^2.0.6",
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"date-fns": "^2.14.0",
"highlight.js": "^10.2.1",
"lodash": "^4.17.21",
"mockjs": "^1.1.0",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"regenerator-runtime": "^0.13.7",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.2",
"viser-vue": "^2.4.8",
"vue": "^2.6.11",
"vue-i18n": "^8.18.2",
"vue-router": "^3.3.4",
"vuedraggable": "^2.23.2",
"vuex": "^3.4.0"
},
"devDependencies": {
"@ant-design/colors": "^4.0.1",
"@babel/eslint-parser": "^7.14.7",
"@vue/cli-plugin-babel": "^4.4.0",
"@vue/cli-plugin-eslint": "^4.4.0",
"@vue/cli-service": "^4.4.0",
"@vuepress/plugin-back-to-top": "^1.5.2",
"autoprefixer": "^9.8.6",
"babel-plugin-transform-remove-console": "^6.9.4",
"babel-polyfill": "^6.26.0",
"compression-webpack-plugin": "^2.0.0",
"deepmerge": "^4.2.2",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-vue": "^6.2.2",
"fast-deep-equal": "^3.1.3",
"gh-pages": "^3.1.0",
"less-loader": "^6.1.1",
"style-resources-loader": "^1.3.2",
"vue-cli-plugin-style-resources-loader": "^0.1.4",
"vue-template-compiler": "^2.6.11",
"vuepress": "^1.5.2",
"webpack-theme-color-replacer": "^1.3.12",
"whatwg-fetch": "^3.0.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {
"no-unused-vars": "off"
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
], ],
"lint-staged": { "parserOptions": {
"*.{js,jsx,vue}": [ "parser": "@babel/eslint-parser"
"vue-cli-service lint", },
"git add" "rules": {
] "no-unused-vars": "off"
} }
} },
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
],
"lint-staged": {
"*.{js,jsx,vue}": [
"vue-cli-service lint",
"git add"
]
}
}
\ No newline at end of file
...@@ -18,6 +18,7 @@ specifiers: ...@@ -18,6 +18,7 @@ specifiers:
clipboard: ^2.0.6 clipboard: ^2.0.6
compression-webpack-plugin: ^2.0.0 compression-webpack-plugin: ^2.0.0
core-js: ^3.6.5 core-js: ^3.6.5
cronstrue: ^1.106.0
crypto-js: ^4.0.0 crypto-js: ^4.0.0
date-fns: ^2.14.0 date-fns: ^2.14.0
deepmerge: ^4.2.2 deepmerge: ^4.2.2
...@@ -55,6 +56,7 @@ dependencies: ...@@ -55,6 +56,7 @@ dependencies:
axios: 0.21.1 axios: 0.21.1
clipboard: 2.0.8 clipboard: 2.0.8
core-js: registry.nlark.com/core-js/3.15.2 core-js: registry.nlark.com/core-js/3.15.2
cronstrue: registry.nlark.com/cronstrue/1.114.0
crypto-js: 4.0.0 crypto-js: 4.0.0
date-fns: registry.nlark.com/date-fns/2.22.1 date-fns: registry.nlark.com/date-fns/2.22.1
highlight.js: registry.nlark.com/highlight.js/10.7.3 highlight.js: registry.nlark.com/highlight.js/10.7.3
...@@ -9323,6 +9325,12 @@ packages: ...@@ -9323,6 +9325,12 @@ packages:
version: 3.15.2 version: 3.15.2
requiresBuild: true requiresBuild: true
registry.nlark.com/cronstrue/1.114.0:
resolution: {integrity: sha1-Dmc/pizpAYHDjgfGstf5/HUxU7g=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/cronstrue/download/cronstrue-1.114.0.tgz}
name: cronstrue
version: 1.114.0
dev: false
registry.nlark.com/css-declaration-sorter/4.0.1: registry.nlark.com/css-declaration-sorter/4.0.1:
resolution: {integrity: sha1-wZiUD2OnbX42wecQGLABchBUyyI=, registry: https://registry.npm.taobao.org/, tarball: https://registry.nlark.com/css-declaration-sorter/download/css-declaration-sorter-4.0.1.tgz} resolution: {integrity: sha1-wZiUD2OnbX42wecQGLABchBUyyI=, registry: https://registry.npm.taobao.org/, tarball: https://registry.nlark.com/css-declaration-sorter/download/css-declaration-sorter-4.0.1.tgz}
name: css-declaration-sorter name: css-declaration-sorter
...@@ -10875,6 +10883,9 @@ packages: ...@@ -10875,6 +10883,9 @@ packages:
engines: {node: '>= 10'} engines: {node: '>= 10'}
peerDependencies: peerDependencies:
ts-node: '>=9.0.0' ts-node: '>=9.0.0'
peerDependenciesMeta:
ts-node:
optional: true
dependencies: dependencies:
import-cwd: 3.0.0 import-cwd: 3.0.0
lilconfig: registry.nlark.com/lilconfig/2.0.3 lilconfig: registry.nlark.com/lilconfig/2.0.3
...@@ -11819,7 +11830,7 @@ packages: ...@@ -11819,7 +11830,7 @@ packages:
dev: true dev: true
registry.nlark.com/vue-loader/16.3.0: registry.nlark.com/vue-loader/16.3.0:
resolution: {integrity: sha1-LxleS6D7DiY1ltaDDfF9Gjbok2w=, registry: https://registry.npm.taobao.org/, tarball: https://registry.nlark.com/vue-loader/download/vue-loader-16.3.0.tgz} resolution: {integrity: sha1-LxleS6D7DiY1ltaDDfF9Gjbok2w=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/vue-loader/download/vue-loader-16.3.0.tgz}
name: vue-loader name: vue-loader
version: 16.3.0 version: 16.3.0
dependencies: dependencies:
......
...@@ -89,3 +89,59 @@ export function getOrganizationUserApi(id) { ...@@ -89,3 +89,59 @@ export function getOrganizationUserApi(id) {
export function addSpecialitiesStaffsApi(data) { export function addSpecialitiesStaffsApi(data) {
return postReq(`/ranger/inspection/api/v1/specialities/staffs`, data); return postReq(`/ranger/inspection/api/v1/specialities/staffs`, data);
} }
export function getRouteInfoApi(id) {
return getReq(`/ranger/inspection/api/v1/routes/${id}`);
}
export function addRouteInfoApi(data) {
return postReq(`/ranger/inspection/api/v1/routes`, data);
}
export function updateRouteInfoApi(data) {
return putReq(`/ranger/inspection/api/v1/routes`, data);
}
export function getTemplateApi() {
return getReq(
`/ranger/inspection/api/v1/routes/downLoadRouteImportTemplate`,
{},
{ responseType: 'blob' },
);
}
export function exportRouteData(data) {
return getReq(`/ranger/inspection/api/v1/routes/exportRouteData`, data, { responseType: 'blob' });
}
export function updateRouteStateApi(data) {
return putReq(`/ranger/inspection/api/v1/routes/routeState`, data);
}
/**
* 上传文件
*/
export function uploadFileRouteApi(data = {}, file) {
const formData = new FormData();
Object.keys(data).forEach((key) => {
formData.append(key, data[key]);
});
formData.append('file', file);
return postReq('/ranger/inspection/api/v1/routes/upload', formData);
}
export function getRouteSchedulesListApi(data) {
return getReq(`/ranger/inspection/api/v1/route/schedules`, data);
}
export function updateRouteSchedulesStateApi({ id, state }) {
return putReq(`/ranger/inspection/api/v1/route/schedules/${id}?shiftState=${state}`);
}
export function addRouteSchedulesApi(data) {
return postReq(`/ranger/inspection/api/v1/route/schedules`, data);
}
export function updateRouteSchedulesApi(data) {
return postReq(`/ranger/inspection/api/v1/route/schedules`, data);
}
export function getRouteAssemblesApi(data) {
return getReq(`/ranger/inspection/api/v1/route/assembles`, data);
}
export function getRouteAssemblesListApi(data) {
return getReq(`/ranger/inspection/api/v1/route/assembles/assembleList`, data);
}
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
:rowKey="rowKey" :rowKey="rowKey"
:pagination="pagination" :pagination="pagination"
@change="pageChange" @change="pageChange"
v-on="$listeners"
:row-selection="selected ? rowSelection : undefined" :row-selection="selected ? rowSelection : undefined"
> >
<slot /> <slot />
...@@ -54,6 +55,8 @@ ...@@ -54,6 +55,8 @@
</a-table> </a-table>
</my-card> </my-card>
<slot name="other" />
<a-drawer <a-drawer
v-if="$scopedSlots.drawer" v-if="$scopedSlots.drawer"
placement="right" placement="right"
...@@ -61,7 +64,7 @@ ...@@ -61,7 +64,7 @@
:drawerStyle="drawerStyle" :drawerStyle="drawerStyle"
:bodyStyle="bodyStyle" :bodyStyle="bodyStyle"
destroyOnClose destroyOnClose
:width="drawerWidth" :width="dWidth"
@close="hidden" @close="hidden"
:maskClosable="false" :maskClosable="false"
:title="title" :title="title"
...@@ -105,6 +108,10 @@ export default { ...@@ -105,6 +108,10 @@ export default {
default: () => ({}), default: () => ({}),
}, },
noMargin: Boolean, noMargin: Boolean,
otherQuery: {
type: Object,
default: () => ({}),
},
}, },
data() { data() {
...@@ -130,9 +137,20 @@ export default { ...@@ -130,9 +137,20 @@ export default {
}, },
type: null, type: null,
row: null, row: null,
dWidth: this.drawerWidth,
}; };
}, },
watch: {
otherQuery: {
handler(val) {
this.otherQuery = val;
},
deep: true,
immediate: true,
},
},
mounted() { mounted() {
this.getData(); this.getData();
}, },
...@@ -186,14 +204,18 @@ export default { ...@@ -186,14 +204,18 @@ export default {
}, },
async getDataWithPage() { async getDataWithPage() {
const res = await request(this.url, METHOD.GET, { ...this.initQuery, ...this.queryForm }); const res = await request(this.url, METHOD.GET, {
...this.initQuery,
...this.queryForm,
...this.otherQuery,
});
this.total = res.total; this.total = res.total;
if (this.formatData) this.data = this.formatData(res); if (this.formatData) this.data = this.formatData({ ...res });
else this.data = res.records; else this.data = res.records;
}, },
async getDataNoPage() { async getDataNoPage() {
const res = await request(this.url, METHOD.GET, this.queryForm); const res = await request(this.url, METHOD.GET, { ...this.queryForm, ...this.otherQuery });
if (this.formatData) this.data = this.formatData(res); if (this.formatData) this.data = this.formatData(res);
else this.data = res; else this.data = res;
}, },
...@@ -211,6 +233,7 @@ export default { ...@@ -211,6 +233,7 @@ export default {
this.title = this.addBtn?.title ?? defaultTitle; this.title = this.addBtn?.title ?? defaultTitle;
this.type = null; this.type = null;
this.row = null; this.row = null;
this.dWidth = this.drawerWidth;
} }
}, },
...@@ -225,6 +248,10 @@ export default { ...@@ -225,6 +248,10 @@ export default {
this.getData(); this.getData();
}, },
refreshView() {
this.data = [...this.data];
},
addBtnClick() { addBtnClick() {
const { click } = typeof this.addBtn === 'object' ? this.addBtn : {}; const { click } = typeof this.addBtn === 'object' ? this.addBtn : {};
click && click(); click && click();
......
<template>
<Table
url="/ranger/inspection/api/v1/place/page"
:rowKey="rowKey"
:selected.sync="selected"
addBtn
ref="addTable"
:otherQuery="otherQuery"
>
<template #search="{ query }">
<MoreItem label="线路名称">
<a-input v-model="query.inputValue" placeholder="请输入" />
</MoreItem>
</template>
<a-table-column title="地点名称" data-index="placeName" />
<a-table-column title="二维码" data-index="qrCode" />
<a-table-column title="电子标签" data-index="electronicTag" />
</Table>
</template>
<script>
import Table from '@/components/table/table.vue';
import MoreItem from '@/components/table/more_item.vue';
import { updateRouteStateApi } from '@/api';
export default {
components: { Table, MoreItem },
props: {
data: Object,
row: Object,
},
watch: {
row: {
handler(val) {
if (val) {
console.log(val);
} else {
const { regionId } = this.data;
this.otherQuery = { regionId };
this.rowKey = 'placeId';
}
},
deep: true,
immediate: true,
},
},
data() {
return {
selected: {},
otherQuery: {},
rowKey: 'regionId',
};
},
methods: {},
};
</script>
<template>
<Wraper :hidden="hidden" noFooter>
<Table
url="/ranger/inspection/api/v1/route/assembles"
rowKey="assembleId"
:formatData="formatData"
addBtn
ref="assembleTable"
:scroll="{ x: true }"
:otherQuery="getDefaultQuery()"
@expand="expand"
:buttons="buttons"
>
<template #drawer="drawer">
<Add v-bind="drawer" :data="row" />
</template>
<a-table-column title="名称" data-index="assembleObjectName" />
<a-table-column title="顺序">
<template #default="row">
<span v-if="row.assembleObjectType === 'PLACE'">{{ row.assembleOrder }}</span>
<span v-else>-</span>
</template>
</a-table-column>
<a-table-column title="类型">
<template #default="row">
<span v-if="row.assembleObjectType === 'PLACE'">地点</span>
<span v-if="row.assembleObjectType === 'UNIT'">单元</span>
<span v-if="row.assembleObjectType === 'ITEM'">项目</span>
</template>
</a-table-column>
<a-table-column title="免检">
<template #default="row">
<span :style="{ color: '#2db7f5' }" v-if="row.exemptionState === 'YES'">是</span>
<span :style="{ color: '#f5222d' }" v-if="row.exemptionState === 'NO'">否</span>
</template>
</a-table-column>
<a-table-column title="状态">
<template #default="row">
<span :style="{ color: '#2db7f5' }" v-if="row.assembleState === 'VALID'">有效</span>
<span :style="{ color: '#f5222d' }" v-if="row.assembleState === 'INVALID'">无效</span>
</template>
</a-table-column>
<a-table-column title="描述" data-index="assembleDesc" />
</Table>
</Wraper>
</template>
<script>
import Table from '@/components/table/table.vue';
import Wraper from '@/components/table/wraper.vue';
import { getRouteAssemblesListApi } from '@/api';
import Add from './add.vue';
export default {
components: { Wraper, Table, Add },
props: { hidden: Function, row: Object },
data() {
return {
buttons: [
{ label: '新增', click: () => {} },
{ label: '失效', click: () => {} },
{ label: '生效', click: () => {} },
{ label: '置顶', click: () => {} },
{ label: '排序', click: () => {} },
{
type: 'confirm',
url: (row) => `/ranger/inspection/api/v1/routes/${row.routeId}`,
after: this.refresh,
},
],
};
},
mounted() {},
methods: {
getDefaultQuery() {
const { routeId, regionId } = this.row;
return {
parentAssembleObjectType: 'REGION',
parentAssembleObjectId: regionId,
routeId,
};
},
formatData(list) {
return list.records.map((i) => {
return {
...i,
children: [],
};
});
},
async expand(expanded, record) {
const { routeId, assembleObjectType, assembleObjectId, assembleState, exemptionState } = record;
const params = {
routeId,
parentAssembleObjectType: assembleObjectType,
parentAssembleObjectId: assembleObjectId,
assembleObjectType: assembleObjectType === 'PLACE' ? 'UNIT' : 'ITEM',
};
const resp = await getRouteAssemblesListApi(params);
const newData = resp.map((i) => {
return {
...i,
children: assembleObjectType === 'PLACE' ? [] : undefined,
assembleState: assembleState === 'INVALID' ? assembleState : i.assembleState,
exemptionState: exemptionState === 'NO' ? exemptionState : i.exemptionState,
};
});
record.children = newData;
this.$refs.assembleTable?.refreshView();
},
},
};
</script>
<template>
<Table
url="/ranger/inspection/api/v1/specialities/staffs"
rowKey="staffId"
ref="table"
:defaultQuery="defaultQuery"
:width="552"
>
<a-table-column title="部门" data-index="orgName" />
<a-table-column title="用户姓名" data-index="staffName" />
</Table>
</template>
<script>
import Table from '@/components/table/table.vue';
export default {
components: { Table },
props: { hidden: Function, row: Object },
watch: {
row: {
handler(val) {
console.log(val);
this.defaultQuery = { specialityId: val.specialityId };
},
deep: true,
immediate: true,
},
},
data() {
return {
defaultQuery: {},
};
},
mounted() {},
methods: {},
};
</script>
<template>
<Drawer ref="drawerRef" v-model="visible" title="新增" :onOk="submit" :colesAfter="refresh">
<a-form-model layout="vertical" :model="form" :rules="rules" ref="DrawerForm">
<a-form-model-item label="班组" prop="shiftType">
<a-select v-model="form.shiftType" :disabled="isView">
<a-select-option key="DAY" value="DAY">白班</a-select-option>
<a-select-option key="MIDDLE" value="MIDDLE">中班</a-select-option>
<a-select-option key="NIGHT" value="NIGHT">晚班</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="生成第二天线路" prop="isNextDay">
<a-select v-model="form.isNextDay" :disabled="isView">
<a-select-option key="YES" value="YES"></a-select-option>
<a-select-option key="NO" value="NO"></a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="生成第二天线路" prop="scheduleRule">
<Acron v-model="form.scheduleRule" :disabled="isView" @input="onChang" />
</a-form-model-item>
<a-form-model-item prop="scheduleDescription">
<a-input v-model="form.scheduleDescription" :disabled="true" />
</a-form-model-item>
</a-form-model>
</Drawer>
</template>
<script>
import cronstrue from 'cronstrue/i18n';
import Lang from '@/utils/langUtils';
import Drawer from '@/components/table/drawer.vue';
import FormMixin from '@/components/FormMixin';
import { addRouteSchedulesApi } from '@/api';
import Acron from '@/components/Acron/index';
const langType = {
en: 'en',
zh: 'zh_CN',
};
export default {
components: { Drawer, Acron },
props: {
refresh: Function,
row: Object,
},
mixins: [FormMixin],
data() {
return {
visible: false,
form: {},
rules: {
shiftType: [{ required: true, message: 'Please select Activity zone', trigger: 'change' }],
isNextDay: [{ required: true, message: 'Please select Activity zone', trigger: 'change' }],
scheduleRule: [{ required: true, message: 'Please select Activity zone', trigger: 'change' }],
},
};
},
async mounted() {},
methods: {
open() {
this.form = {};
this.visible = true;
},
add() {
const { routeId } = this.row;
return addRouteSchedulesApi({ ...this.form, routeId });
},
onChang(val) {
const str = cronstrue.toString(val, { locale: langType[Lang.get().substr(0, 2)] });
this.form = { ...this.form, scheduleDescription: `${str} 执行一次` };
},
},
};
</script>
<template>
<Wraper :hidden="hidden" noFooter>
<a-button class="tw-mb-4" type="primary" @click="onAdd">新增</a-button>
<addDrawer ref="addDrawer" :row="row" :refresh="getList" />
<a-list :data-source="data" :grid="{ gutter: 16, xs: 1, sm: 1, md: 1, lg: 1, xl: 1, xxl: 1 }">
<a-list-item slot="renderItem" slot-scope="item">
<a-card>
<template #title>
<a-row>
<a-col :span="12">
<a-tag v-if="item.shiftState === 'VALID'" color="#87d068"> 有效 </a-tag>
<a-tag v-else color="#f50"> 无效 </a-tag>
<span v-if="item.shiftType === 'DAY'">白班</span>
<span v-if="item.shiftType === 'MIDDLE'">中班</span>
<span v-if="item.shiftType === 'NIGHT'">晚班</span>
</a-col>
<a-col :span="12" class="tw-text-right">
<a-space>
<PopconfirmDelete
:url="`/ranger/inspection/api/v1/route/schedules/${item.shiftId}`"
:cb="getList"
/>
<a
v-if="item.shiftState === 'INVALID'"
@click="() => scheduleUpdateState(item.shiftId, 'VALID')"
>生效</a
>
<a
v-if="item.shiftState === 'VALID'"
@click="() => scheduleUpdateState(item.shiftId, 'INVALID')"
>失效</a
>
</a-space>
</a-col>
</a-row>
</template>
<div>{{ item.scheduleRule }}</div>
<div>{{ item.scheduleDescription }}</div>
<div>{{ item.isNextDay === 'YES' && '生成第二天线路' }}</div>
</a-card>
</a-list-item>
</a-list>
</Wraper>
</template>
<script>
import PopconfirmDelete from '@/components/popconfirm_delete/index.vue';
import Wraper from '@/components/table/wraper.vue';
import { getRouteSchedulesListApi, updateRouteSchedulesStateApi } from '@/api';
import addDrawer from './add.vue';
export default {
components: { Wraper, PopconfirmDelete, addDrawer },
props: { hidden: Function, row: Object },
data() {
return {
data: [],
loading: false,
};
},
mounted() {
this.getList();
},
methods: {
async getList() {
const { routeId } = this.row;
this.loading = true;
const data = await getRouteSchedulesListApi({ routeId, pageNum: 1, pageSize: 10 });
this.data = data.records;
this.loading = false;
},
async scheduleUpdateState(id, state) {
await updateRouteSchedulesStateApi({ id, state });
this.getList();
},
onAdd() {
this.$refs.addDrawer?.open();
},
},
};
</script>
<template> <template>
<Wraper :hidden="hidden" :onOk="submit" :refresh="refresh" :noFooter="isView"> <Wraper :hidden="hidden" :onOk="submit" :refresh="refresh" :noFooter="isView">
<a-form-model layout="vertical" :model="form" :rules="rules" ref="form"> <a-form-model layout="vertical" :model="form" :rules="rules" ref="form">
<a-form-model-item label="地点名称" prop="placeName"> <a-form-model-item label="线路名称" prop="routeName">
<a-input v-model="form.placeName" :disabled="isView" /> <a-input v-model="form.routeName" :disabled="isView" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="所属地区" prop="regionId"> <a-form-model-item label="所属地区" prop="regionId">
<UrlSelect <UrlSelect
v-model="form.regionId" v-model="form.regionId"
...@@ -14,11 +13,33 @@ ...@@ -14,11 +13,33 @@
:disabled="isView" :disabled="isView"
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="二维码" prop="qrCode"> <a-form-model-item label="专业" prop="specialityId">
<a-input v-model="form.qrCode" :disabled="isView" /> <UrlSelect
v-model="form.specialityId"
:url="
form.regionId
? `/ranger/inspection/api/v1/specialities/valid/regions/${form.regionId}/list`
: ''
"
labelFiled="specialityName"
valueFiled="specialityId"
:disabled="isView"
/>
</a-form-model-item>
<a-form-model-item label="分配方式" prop="dispatchType">
<a-select v-model="form.dispatchType" style="width: 100%" :disabled="isView">
<a-select-option key="PERSON" value="PERSON">按人分配</a-select-option>
<a-select-option key="SPECIALITY" value="SPECIALITY">按专业分配</a-select-option>
</a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="二维码" prop="electronicTag"> <a-form-model-item label="过期方式" prop="expirationType">
<a-input v-model="form.electronicTag" :disabled="isView" /> <a-select v-model="form.expirationType" style="width: 100%" :disabled="isView">
<a-select-option key="NEXT" value="NEXT">下次任务开始过期</a-select-option>
<a-select-option key="ONE_DAY" value="ONE_DAY">一天后过期</a-select-option>
<a-select-option key="SEVEN_DAY" value="SEVEN_DAY">七天后过期</a-select-option>
<a-select-option key="FIFTEEN_DAY" value="FIFTEEN_DAY">十五天后过期</a-select-option>
<a-select-option key="NEVER" value="NEVER">不过期</a-select-option>
</a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="备注" prop="remark"> <a-form-model-item label="备注" prop="remark">
<a-textarea placeholder="Basic usage" :rows="4" v-model="form.remark" :disabled="isView" /> <a-textarea placeholder="Basic usage" :rows="4" v-model="form.remark" :disabled="isView" />
...@@ -30,7 +51,7 @@ ...@@ -30,7 +51,7 @@
<script> <script>
import Wraper from '@/components/table/wraper.vue'; import Wraper from '@/components/table/wraper.vue';
import UrlSelect from '@/components/MySelect/url_select.vue'; import UrlSelect from '@/components/MySelect/url_select.vue';
import { addPlaceApi, editPlaceApi, getPlaceInfoApi } from '@/api'; import { addRouteInfoApi, updateRouteInfoApi, getRouteInfoApi } from '@/api';
export default { export default {
components: { Wraper, UrlSelect }, components: { Wraper, UrlSelect },
...@@ -38,10 +59,11 @@ export default { ...@@ -38,10 +59,11 @@ export default {
data: () => ({ data: () => ({
form: {}, form: {},
rules: { rules: {
placeName: [{ required: true }], routeName: [{ required: true }],
regionId: [{ required: true }], regionId: [{ required: true }],
qrCode: [{ required: true }], specialityId: [{ required: true }],
electronicTag: [{ required: true }], dispatchType: [{ required: true }],
expirationType: [{ required: true }],
}, },
}), }),
...@@ -59,15 +81,15 @@ export default { ...@@ -59,15 +81,15 @@ export default {
async mounted() { async mounted() {
if (!this.isAdd) { if (!this.isAdd) {
this.form = await getPlaceInfoApi(this.row.placeId); this.form = await getRouteInfoApi(this.row.routeId);
} }
}, },
methods: { methods: {
async submit() { async submit() {
await this.$refs.form.validate(); await this.$refs.form.validate();
if (this.isAdd) return addPlaceApi(this.form); if (this.isAdd) return addRouteInfoApi(this.form);
if (this.isEdit) return editPlaceApi(this.form); if (this.isEdit) return updateRouteInfoApi(this.form);
}, },
}, },
}; };
......
<template>
<Wraper :hidden="hidden" noFooter>
<a-list :data-source="data" :grid="{ gutter: 16, xs: 1, sm: 1, md: 1, lg: 1, xl: 1, xxl: 1 }">
<a-list-item slot="renderItem" slot-scope="item">
<a-card>
<template #title>
<a-tag v-if="item.exemptionState === 'EFFECTIVE'" color="#87d068"> 有效 </a-tag>
<a-tag v-else color="#f50"> 无效 </a-tag>
{{ `${item.startTime} 至 ${item.endTime}` }}
</template>
{{ item.exemptionReason }}
</a-card>
</a-list-item>
</a-list>
</Wraper>
</template>
<script>
import Wraper from '@/components/table/wraper.vue';
import { getExemptionsListApi } from '@/api';
export default {
components: { Wraper },
props: { hidden: Function, row: Object },
data() {
return {
data: [],
loading: false,
};
},
mounted() {
this.getList();
},
methods: {
async getList() {
const { placeId, regionId } = this.row;
this.loading = true;
const data = await getExemptionsListApi({ placeId, regionId, exemptionType: 'PLACE' });
this.data = data;
this.loading = false;
},
},
};
</script>
<template>
<a-modal v-model="visible" title="导入" @ok="handleOk" destroyOnClose>
<a-form-model layout="vertical" :model="form" :rules="rules" ref="form">
<a-form-model-item label="组织" prop="orgId">
<UrlSelect
v-model="form.orgId"
url="/api/v1/users/organizations"
labelFiled="orgName"
valueFiled="orgId"
/>
</a-form-model-item>
<a-form-model-item label="上传文件" prop="file">
<Upload v-model="form.file" showUploadList :number="1" />
<template #extra>
<a-button type="link" @click="getTemplate"> 下载模板 </a-button>
</template>
</a-form-model-item>
</a-form-model>
</a-modal>
</template>
<script>
import { getTemplateApi, uploadFileRouteApi } from '@/api';
import UrlSelect from '@/components/MySelect/url_select.vue';
import { downloadFile } from '@/utils';
import Upload from './uploadList.vue';
export default {
components: { UrlSelect, Upload },
data() {
return {
visible: false,
form: {},
rules: {
orgId: [{ required: true }],
file: [{ required: true }],
},
};
},
props: {
afterSubmit: Function,
},
methods: {
showModal() {
this.form = {};
console.log(this.form);
this.visible = true;
},
async handleOk(e) {
await this.$refs.form.validate();
const { file, ...rest } = this.form;
await uploadFileRouteApi({ ...rest }, file[0].oFile);
this.afterSubmit && this.afterSubmit();
this.$message.info('操作成功!');
this.closeModal();
},
closeModal() {
this.visible = false;
},
async getTemplate() {
const resp = await getTemplateApi();
downloadFile(resp, 'xlsx');
},
},
};
</script>
<template> <template>
<Table <Table
url="/ranger/inspection/api/v1/place/page" url="/ranger/inspection/api/v1/routes"
rowKey="placeId" rowKey="routeId"
:selected.sync="selected" :selected.sync="selected"
addBtn addBtn
:buttons="buttons" :buttons="buttons"
ref="table" ref="table"
:scroll="{ x: true }"
> >
<template #search="{ query }"> <template #search="{ query }">
<MoreItem label="状态">
<a-select v-model="query.routeState" style="width: 100%">
<a-select-option key="VALID" value="VALID">有效</a-select-option>
<a-select-option key="INVALID" value="INVALID">无效</a-select-option>
</a-select>
</MoreItem>
<MoreItem label="地区"> <MoreItem label="地区">
<UrlSelect <UrlSelect
v-model="query.regionId" v-model="query.regionId"
...@@ -17,26 +24,65 @@ ...@@ -17,26 +24,65 @@
placeholder="选择地区" placeholder="选择地区"
/> />
</MoreItem> </MoreItem>
<MoreItem label="搜索"> <MoreItem label="专业">
<a-input v-model="query.inputValue" placeholder="请输入地点名称/二维码/电子标签" /> <UrlSelect
v-model="query.specialityId"
:url="
query.regionId
? `/ranger/inspection/api/v1/specialities/valid/regions/${query.regionId}/list`
: ''
"
labelFiled="specialityName"
valueFiled="specialityId"
placeholder="选择专业"
/>
</MoreItem>
<MoreItem label="线路名称">
<a-input v-model="query.inputValue" placeholder="请输入" />
</MoreItem> </MoreItem>
</template> </template>
<template #operation> <template #operation>
<a-button @click="download">导出</a-button> <a-button type="primary" @click="onImportFlie">导入</a-button>
<a-button @click="download" :disabled="!(selected.keys && selected.keys.length !== 0)">
导出
</a-button>
<a-button
@click="() => onChangeState('VALID')"
:disabled="!(selected.keys && selected.keys.length !== 0)"
>
生效
</a-button>
<a-button
@click="() => onChangeState('INVALID')"
:disabled="!(selected.keys && selected.keys.length !== 0)"
>
失效
</a-button>
</template> </template>
<template #drawer="drawer"> <template #drawer="drawer">
<AddAndEdit v-if="drawer.type !== 'exempt'" v-bind="drawer" /> <Assemble v-if="['assemble'].includes(drawer.type)" v-bind="drawer" />
<Exempt v-else v-bind="drawer" /> <Personnel v-else-if="['personnel'].includes(drawer.type)" v-bind="drawer" />
<Schedule v-else-if="['schedule'].includes(drawer.type)" v-bind="drawer" />
<AddAndEdit v-else-if="drawer.type !== 'exempt'" v-bind="drawer" />
<!-- <Exempt v-else v-bind="drawer" /> -->
</template> </template>
<a-table-column title="地点名称" data-index="placeName" /> <a-table-column title="线路名称" data-index="routeName" />
<a-table-column title="所属地区" data-index="regionName" /> <a-table-column title="专业" data-index="specialityName" />
<a-table-column title="二维码" data-index="qrCode" /> <a-table-column title="地区" data-index="regionName" />
<a-table-column title="电子标签" data-index="electronicTag" /> <a-table-column title="状态">
<template #default="row">
<span v-if="row.routeState === 'VALID'">有效</span>
<span v-if="row.routeState === 'INVALID'">无效</span>
</template>
</a-table-column>
<a-table-column title="修改人" data-index="editorName" /> <a-table-column title="修改人" data-index="editorName" />
<a-table-column title="修改时间" data-index="editTime" /> <a-table-column title="修改时间" data-index="editTime" />
<template #other>
<ImportFlie ref="importFlie" :afterSubmit="rest" />
</template>
</Table> </Table>
</template> </template>
...@@ -44,21 +90,27 @@ ...@@ -44,21 +90,27 @@
import Table from '@/components/table/table.vue'; import Table from '@/components/table/table.vue';
import UrlSelect from '@/components/MySelect/url_select.vue'; import UrlSelect from '@/components/MySelect/url_select.vue';
import MoreItem from '@/components/table/more_item.vue'; import MoreItem from '@/components/table/more_item.vue';
import { downloadFileByUrl } from '@/utils'; import { exportRouteData, updateRouteStateApi } from '@/api';
import { downloadFile } from '@/utils';
import AddAndEdit from './add_edit.vue'; import AddAndEdit from './add_edit.vue';
import Exempt from './exempt.vue'; import Schedule from './Schedule/index.vue';
import Personnel from './Personnel/index.vue';
import Assemble from './Assemble/index.vue';
import ImportFlie from './importFlie.vue';
export default { export default {
components: { Table, UrlSelect, MoreItem, AddAndEdit, Exempt }, components: { Table, UrlSelect, MoreItem, AddAndEdit, ImportFlie, Schedule, Personnel, Assemble },
data() { data() {
return { return {
buttons: [ buttons: [
{ label: '编辑', click: this.edit }, { label: '编辑', click: this.edit },
{ label: '详情', click: this.view }, { label: '详情', click: this.view },
{ label: '免检', click: this.exempt }, { label: '编排', click: this.assemble },
{ label: '调度', click: this.schedule },
{ label: '人员', click: this.personnel },
{ {
type: 'confirm', type: 'confirm',
url: (row) => `/ranger/inspection/api/v1/place/${row.placeId}`, url: (row) => `/ranger/inspection/api/v1/routes/${row.routeId}`,
after: this.refresh, after: this.refresh,
}, },
], ],
...@@ -75,16 +127,36 @@ export default { ...@@ -75,16 +127,36 @@ export default {
view(row) { view(row) {
this.$refs.table.show({ row, title: '查看', type: 'view' }); this.$refs.table.show({ row, title: '查看', type: 'view' });
}, },
exempt(row) { schedule(row) {
this.$refs.table.show({ row, title: '免检', type: 'exempt' }); this.$refs.table.show({ row, title: '调度', type: 'schedule' });
},
personnel(row) {
this.$refs.table.show({ row, title: '调度', type: 'personnel' });
}, },
download() { assemble(row) {
this.$refs.table.show({ row, title: '编排', type: 'assemble', dWidth: 1200 });
},
async download() {
if (!this.selected?.keys?.length) return this.$message.error('请选择需要导出的数据'); if (!this.selected?.keys?.length) return this.$message.error('请选择需要导出的数据');
downloadFileByUrl( const resp = await exportRouteData({ routeIdList: this.selected.keys.join(',') });
`/ranger/inspection/api/v1/place/exportQrCodeData?placeIdList=${this.selected.keys.join( downloadFile(resp, 'xlsx');
',', },
)}`, async onChangeState(state) {
); const data = {
routeIdList: this.selected.keys,
routeState: state,
};
await updateRouteStateApi(data);
this.$message.info('操作成功!');
this.rest();
},
rest() {
this.$refs.table.reset();
},
onImportFlie() {
this.$refs.importFlie?.showModal();
}, },
}, },
}; };
......
<template>
<a-upload
:customRequest="customRequest"
:showUploadList="showUploadList"
:fileList="fileList"
:remove="onRemove"
v-bind="$attrs"
list-type="picture"
>
<slot>
<a-button v-if="fileList.length < number"> <a-icon type="upload" /> 上传 </a-button>
</slot>
</a-upload>
</template>
<script>
export default {
props: {
value: [String, Array],
modelName: {
type: String,
default: 'adminSystem',
},
showUploadList: {
type: [Object, Boolean],
default: false,
},
number: {
type: Number,
default: 5,
},
},
model: {
prop: 'value',
event: 'change',
},
data() {
return {
fileList: [],
};
},
watch: {
value: {
handler(val) {
this.fileList = val || [];
},
immediate: true,
},
},
methods: {
async customRequest(info) {
const { file } = info;
const data = {
uid: file.uid,
status: 'done',
name: file.name,
oFile: file,
};
this.fileList = [...this.fileList, data];
this.$emit('change', this.fileList);
},
onRemove(file) {
const newArr = this.fileList.filter((i) => i.uid !== file.uid);
this.fileList = [...newArr];
this.$emit('change', this.fileList);
},
},
};
</script>
...@@ -37,7 +37,7 @@ export function clearUserInfo() { ...@@ -37,7 +37,7 @@ export function clearUserInfo() {
export function convertListToTree(menuList, filterMenu = false, toMenuData = false) { export function convertListToTree(menuList, filterMenu = false, toMenuData = false) {
let tempMenu = [...menuList]; let tempMenu = [...menuList];
if (filterMenu) { if (filterMenu) {
tempMenu = tempMenu.filter(m => m.menuType !== 'MENU'); tempMenu = tempMenu.filter((m) => m.menuType !== 'MENU');
} }
for (const menu of menuList) { for (const menu of menuList) {
if (toMenuData) { if (toMenuData) {
...@@ -45,15 +45,15 @@ export function convertListToTree(menuList, filterMenu = false, toMenuData = fal ...@@ -45,15 +45,15 @@ export function convertListToTree(menuList, filterMenu = false, toMenuData = fal
menu.path = menu.menuUrl; menu.path = menu.menuUrl;
} }
if (menu.parentMenuId === 0) continue; if (menu.parentMenuId === 0) continue;
const parent = menuList.find(m => m.menuId === menu.parentMenuId); const parent = menuList.find((m) => m.menuId === menu.parentMenuId);
parent.children ? parent.children.push(menu) : (parent.children = [menu]); parent.children ? parent.children.push(menu) : (parent.children = [menu]);
} }
return tempMenu.filter(m => m.parentMenuId === 0); return tempMenu.filter((m) => m.parentMenuId === 0);
} }
export function EMPTY_FUN() {} export function EMPTY_FUN() {}
export const isFunction = val => typeof val === 'function'; export const isFunction = (val) => typeof val === 'function';
export function arrayToTree(options) { export function arrayToTree(options) {
options = JSON.parse(JSON.stringify(options)); options = JSON.parse(JSON.stringify(options));
this.data = options.data || []; this.data = options.data || [];
...@@ -64,10 +64,10 @@ export function arrayToTree(options) { ...@@ -64,10 +64,10 @@ export function arrayToTree(options) {
this.rootValue = options.rootValue || '0'; this.rootValue = options.rootValue || '0';
this.treeData = []; this.treeData = [];
this.indexStorage = {}; this.indexStorage = {};
this.getDataBykey = function(key) { this.getDataBykey = function (key) {
return this.indexStorage[key]; return this.indexStorage[key];
}; };
this.setMapping = function() { this.setMapping = function () {
for (let i = 0; i < this.data.length; i++) { for (let i = 0; i < this.data.length; i++) {
var item = this.data[i]; var item = this.data[i];
for (const x in this.maping) { for (const x in this.maping) {
...@@ -78,14 +78,14 @@ export function arrayToTree(options) { ...@@ -78,14 +78,14 @@ export function arrayToTree(options) {
if (this.maping) { if (this.maping) {
this.setMapping(); this.setMapping();
} }
this.setIndexStorage = function() { this.setIndexStorage = function () {
for (let i = 0; i < this.data.length; i++) { for (let i = 0; i < this.data.length; i++) {
this.indexStorage[this.data[i][this.key]] = this.data[i]; // 以id作为索引存储元素,可以无需遍历直接定位元素 this.indexStorage[this.data[i][this.key]] = this.data[i]; // 以id作为索引存储元素,可以无需遍历直接定位元素
} }
}; };
this.setIndexStorage(); this.setIndexStorage();
// 利用数组浅拷贝 // 利用数组浅拷贝
this.toTree = function() { this.toTree = function () {
const THISDATA = JSON.parse(JSON.stringify(this.data)); const THISDATA = JSON.parse(JSON.stringify(this.data));
for (let i = 0; i < this.data.length; i++) { for (let i = 0; i < this.data.length; i++) {
let currentElement = this.data[i]; let currentElement = this.data[i];
...@@ -115,9 +115,9 @@ export function arrayToTree(options) { ...@@ -115,9 +115,9 @@ export function arrayToTree(options) {
// select组件 数据格式化 // select组件 数据格式化
export const formatObj = (ArrObj, obj) => { export const formatObj = (ArrObj, obj) => {
const newData = [...ArrObj]; const newData = [...ArrObj];
const newDataOne = newData.map(i => { const newDataOne = newData.map((i) => {
const newObj = { ...i }; const newObj = { ...i };
Object.keys(obj).forEach(key => { Object.keys(obj).forEach((key) => {
newObj[key] = i[obj[key]]; newObj[key] = i[obj[key]];
}); });
return newObj; return newObj;
...@@ -139,3 +139,21 @@ export function downloadFileByUrl(url) { ...@@ -139,3 +139,21 @@ export function downloadFileByUrl(url) {
aEle.setAttribute('href', url); aEle.setAttribute('href', url);
aEle.click(); aEle.click();
} }
/**
* 下载文件
* @param {data} data 文件流
* @param {string} type 文件后缀
*/
export function downloadFile(data, type) {
const url = window.URL.createObjectURL(data);
// 生成一个a标签
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
// 生成时间戳
const timestamp = new Date().getTime();
link.download = `${timestamp}.${type}`;
document.body.appendChild(link);
link.click();
}
...@@ -39,6 +39,9 @@ function loadResponseInterceptor({ router }) { ...@@ -39,6 +39,9 @@ function loadResponseInterceptor({ router }) {
const { data } = response; const { data } = response;
// 2xx 范围内的状态码都会触发该函数。 // 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么 // 对响应数据做点什么
if (response.headers['content-disposition']) {
return data;
}
if (data.code === 'sys.success') { if (data.code === 'sys.success') {
return data.data; return data.data;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment