diff --git a/src/api/bst/device.js b/src/api/bst/device.js new file mode 100644 index 0000000..9322dc6 --- /dev/null +++ b/src/api/bst/device.js @@ -0,0 +1,80 @@ +import request from '@/utils/request' + +// 查询设备列表 +export function listDevice(query) { + return request({ + url: '/bst/device/list', + method: 'get', + params: query + }) +} + +// 查询设备详细 +export function getDevice(id) { + return request({ + url: '/bst/device/' + id, + method: 'get' + }) +} + +// 新增设备 +export function addDevice(data) { + return request({ + url: '/bst/device', + method: 'post', + data: data + }) +} + +// 修改设备 +export function updateDevice(data) { + return request({ + url: '/bst/device', + method: 'put', + data: data + }) +} + +// 删除设备 +export function delDevice(id) { + return request({ + url: '/bst/device/' + id, + method: 'delete' + }) +} + +// 设备入仓 +export function inDevice(ids) { + return request({ + url: '/bst/device/in', + method: 'put', + data: ids + }) +} + +// 设备出仓 +export function outDevice(ids) { + return request({ + url: '/bst/device/out', + method: 'put', + data: ids + }) +} + +// 设备禁用 +export function disableDevice(ids) { + return request({ + url: '/bst/device/disable', + method: 'put', + data: ids + }) +} + +// 设备启用 +export function enableDevice(ids) { + return request({ + url: '/bst/device/enable', + method: 'put', + data: ids + }) +} diff --git a/src/api/bst/deviceIot.js b/src/api/bst/deviceIot.js new file mode 100644 index 0000000..a6d9eac --- /dev/null +++ b/src/api/bst/deviceIot.js @@ -0,0 +1,55 @@ +import request from '@/utils/request' + +// 管理员开锁 +export function unlockDevice(data) { + return request({ + url: '/bst/device/iot/unlock', + method: 'put', + params: data + }) +} + +// 管理员锁车 +export function lockDevice(data) { + return request({ + url: '/bst/device/iot/lock', + method: 'put', + params: data + }) +} + +// 管理员响铃寻车 +export function ringDevice(data) { + return request({ + url: '/bst/device/iot/ring', + method: 'put', + params: data + }) +} + +// 管理员重启 +export function rebootDevice(data) { + return request({ + url: '/bst/device/iot/reboot', + method: 'put', + params: data + }) +} + +// 管理员开坐垫锁 +export function unlockSeatDevice(data) { + return request({ + url: '/bst/device/iot/unlockSeat', + method: 'put', + params: data + }) +} + +// 管理员刷新 +export function refreshDevice(data) { + return request({ + url: '/bst/device/iot/refresh', + method: 'put', + params: data + }) +} diff --git a/src/api/bst/suit.js b/src/api/bst/suit.js index 2303b02..50ed796 100644 --- a/src/api/bst/suit.js +++ b/src/api/bst/suit.js @@ -9,6 +9,18 @@ export function listSuit(query) { }) } +// 查询套餐列表ByIds +export function listSuitByIds(ids) { + return request({ + url: '/bst/suit/listByIds', + headers: { + repeatSubmit: false, + }, + method: 'post', + data: ids + }) +} + // 查询套餐详细 export function getSuit(id) { return request({ diff --git a/src/components/Business/Area/AreaRemoteSelect.vue b/src/components/Business/Area/AreaRemoteSelect.vue index 4dc4b5e..8b4a3de 100644 --- a/src/components/Business/Area/AreaRemoteSelect.vue +++ b/src/components/Business/Area/AreaRemoteSelect.vue @@ -6,9 +6,12 @@ :multiple="multiple" :loading="loading" @change="handleChange" + @visible-change="handleVisibleChange" + remote + :remote-method="remoteMethod" > <div class="select-footer"> - <div style="text-align: center; color: #8492a6; font-size: 13px; line-height: 28px; "> + <div style="text-align: center; color: #8492a6; font-size: 13px; "> 共{{ total }}条数据 </div> <el-button v-if="multiple && !isEmpty(options)" style="margin-left: 10px;" size="mini" type="text" @click.stop="handleSelectAll"> @@ -83,20 +86,24 @@ export default { return this.multiple && this.options.length > 0 && Array.isArray(this.value) && this.value.length === this.options.length; } }, - watch: { - query: { - handler(nv) { - this.queryParams = { - ...this.queryParams, - ...nv - } - this.getOptions(); - }, - immediate: true + created() { + if (!isEmpty(this.initOptions)) { + this.options = this.initOptions; } }, methods: { isEmpty, + // 远程搜索 + remoteMethod(val) { + this.queryParams.keyword = val; + this.getOptions(); + }, + // 下拉框可见性变化 + handleVisibleChange(visible) { + if (visible) { + this.getOptions(); + } + }, // 全选 handleSelectAll() { if (this.isAllSelected) { @@ -107,9 +114,15 @@ export default { } }, handleChange(value) { - let list = this.options.filter(item => value.includes(item.id)); - this.$emit('change', list); + if (this.multiple) { + let list = this.options.filter(item => value.includes(item.id)); + this.$emit('change', list); + } else { + let item = this.options.find(item => value.includes(item.id)); + this.$emit('change', item); + } }, + // 获取选项 getOptions() { this.loading = true; this.queryParams = { @@ -129,13 +142,11 @@ export default { <style lang="scss" scoped> .select-footer { - padding: 5px 12px; + padding: 2px 12px; border-bottom: 1px solid #EBEEF5; display: flex; justify-content: flex-end; align-items: center; -} -.user-name { - padding-left: 6px; + line-height: 1em; } </style> \ No newline at end of file diff --git a/src/components/Business/Model/ModelRemoteSelect.vue b/src/components/Business/Model/ModelRemoteSelect.vue new file mode 100644 index 0000000..42cfb4b --- /dev/null +++ b/src/components/Business/Model/ModelRemoteSelect.vue @@ -0,0 +1,152 @@ +<template> + <el-select + v-model="selectedValue" + placeholder="请选择" + filterable + :multiple="multiple" + :loading="loading" + @change="handleChange" + @visible-change="handleVisibleChange" + remote + :remote-method="remoteMethod" + > + <div class="select-footer"> + <div style="text-align: center; color: #8492a6; font-size: 13px; "> + 共{{ total }}条数据 + </div> + <el-button v-if="multiple && !isEmpty(options)" style="margin-left: 10px;" size="mini" type="text" @click.stop="handleSelectAll"> + {{ isAllSelected ? '取消全选' : '全选' }} + </el-button> + </div> + <el-option + v-for="item in options" + :key="item.id" + :value="item.id" + :label="item.name" + /> + <el-option v-if="isEmpty(value) && isEmpty(options)" style="display:none" disabled :value="null"></el-option> + </el-select> +</template> + +<script> +import { listModel } from '@/api/bst/model'; +import Avatar from '@/components/Avatar'; +import {isEmpty} from '@/utils' + +export default { + name: 'AreaRemoteSelect', + components: { + Avatar + }, + props: { + // 区域id + value: { + type: [String, Array], + default: null + }, + // 自定义查询参数 + query: { + type: Object, + default: () => ({}) + }, + // 是否多选 + multiple: { + type: Boolean, + default: false + }, + // 初始化选项 + initOptions: { + type: Array, + default: () => [] + } + }, + data() { + return { + options: [], + total: 0, + loading: false, + queryParams: { + pageNum: 1, + pageSize: 100, + keyword: null + } + } + }, + computed: { + selectedValue: { + get() { + return this.value + }, + set(value) { + this.$emit('input', value) + } + }, + // 是否全选 + isAllSelected() { + return this.multiple && this.options.length > 0 && Array.isArray(this.value) && this.value.length === this.options.length; + } + }, + created() { + if (!isEmpty(this.initOptions)) { + this.options = this.initOptions; + } + }, + methods: { + isEmpty, + // 远程搜索 + remoteMethod(val) { + this.queryParams.keyword = val; + this.getOptions(); + }, + // 下拉框可见性变化 + handleVisibleChange(visible) { + if (visible) { + this.getOptions(); + } + }, + // 全选 + handleSelectAll() { + if (this.isAllSelected) { + this.handleChange([]); + } else { + const allids = this.options.map(item => item.id); + this.handleChange(allids); + } + }, + handleChange(value) { + if (this.multiple) { + let list = this.options.filter(item => value.includes(item.id)); + this.$emit('change', list); + } else { + let item = this.options.find(item => value.includes(item.id)); + this.$emit('change', item); + } + }, + // 获取选项 + getOptions() { + this.loading = true; + this.queryParams = { + ...this.queryParams, + ...this.query + } + listModel(this.queryParams).then(res => { + this.options = res.rows; + this.total = res.total; + }).finally(() => { + this.loading = false; + }); + } + } +} +</script> + +<style lang="scss" scoped> +.select-footer { + padding: 2px 12px; + border-bottom: 1px solid #EBEEF5; + display: flex; + justify-content: flex-end; + align-items: center; + line-height: 1em; +} +</style> \ No newline at end of file diff --git a/src/components/Business/Suit/SuitDialog.vue b/src/components/Business/Suit/SuitDialog.vue new file mode 100644 index 0000000..4cc0011 --- /dev/null +++ b/src/components/Business/Suit/SuitDialog.vue @@ -0,0 +1,175 @@ +<template> + <check-dialog + :show.sync="dialogVisible" + :title="title" + :columns="columns" + :selected-ids="selectedIds" + :list-api="listApi" + :load-api="loadApi" + :query="queryParams" + :custom-query="query" + prop="id" + @confirm="handleConfirm" + :multiple="multiple" + ref="checkDialog" + > + <template #search-form> + <el-form-item label="运营商" prop="userName"> + <el-input + v-model="queryParams.userName" + placeholder="请输入运营商名称" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="套餐名称" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入套餐名称" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="状态" prop="status"> + <el-select + v-model="queryParams.status" + placeholder="请选择状态" + clearable + @change="handleQuery" + > + <el-option + v-for="dict in dict.type.suit_status" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="租赁单位" prop="rentalUnit"> + <el-select + v-model="queryParams.rentalUnit" + placeholder="请选择租赁单位" + clearable + @change="handleQuery" + > + <el-option + v-for="dict in dict.type.suit_rental_unit" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + </template> + + <template #status="{row}"> + <dict-tag :options="dict.type.suit_status" :value="row.status" /> + </template> + <template #rentalUnit="{row}"> + <dict-tag :options="dict.type.suit_rental_unit" :value="row.rentalUnit" /> + </template> + <template #depositAmount="{row}"> + {{ row.depositAmount | fix2 | dv }} 元 + </template> + <template #freeRideTime="{row}"> + {{ row.freeRideTime | dv }} 分钟 + </template> + + </check-dialog> +</template> + +<script> +import { listSuit, listSuitByIds } from "@/api/bst/suit"; +import CheckDialog from "@/components/CheckDialog/index.vue"; +import { isEmpty } from '@/utils/index' + +export default { + name: "SuitDialog", + dicts: ['suit_status', 'suit_rental_unit', 'suit_riding_rule'], + components: { + CheckDialog + }, + props: { + // 弹窗标题 + title: { + type: String, + default: "选择套餐" + }, + // 是否显示弹窗 + show: { + type: Boolean, + default: false + }, + // 默认选中的ID列表 + selectedIds: { + type: [String, Array], + default: null, + }, + // 列表API + listApi: { + type: Function, + default: listSuit + }, + // 加载API + loadApi: { + type: Function, + default: listSuitByIds + }, + // 是否多选 + multiple: { + type: Boolean, + default: false + }, + // 查询参数 + query: { + type: Object, + default: () => ({}) + }, + }, + data() { + return { + // 查询参数 + queryParams: { + pageNum: 1, + pageSize: 10, + name: null, + userName: null, + status: null, + rentalUnit: null + }, + // 列信息 + columns: [ + {key: 'id', visible: false, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"}, + {key: 'name', visible: true, label: '名称', minWidth: "200", sortable: true, overflow: false, align: 'left', width: null}, + {key: 'userName', visible: true, label: '运营商', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'depositAmount', visible: true, label: '预存', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'rentalUnit', visible: true, label: '租赁单位', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'freeRideTime', visible: true, label: '免费时长', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'status', visible: true, label: '状态', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'createTime', visible: true, label: '创建时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: null} + ], + } + }, + computed: { + dialogVisible: { + get() { + return this.show; + }, + set(val) { + this.$emit("update:show", val); + } + } + }, + methods: { + isEmpty, + // 确认选择 + handleConfirm(selection) { + this.$emit('confirm', selection); + }, + // 处理查询 + handleQuery() { + this.$refs.checkDialog.handleQuery(); + } + } +} +</script> diff --git a/src/components/Business/Suit/SuitInput.vue b/src/components/Business/Suit/SuitInput.vue new file mode 100644 index 0000000..40b6e74 --- /dev/null +++ b/src/components/Business/Suit/SuitInput.vue @@ -0,0 +1,84 @@ +<template> + <div> + <el-input + :value="text" + @focus="onOpen" + placeholder="点击选择套餐" + :disabled="disabled" + /> + + <suit-dialog + :show.sync="showDialog" + @confirm="handleConfirm" + :selected-ids="value" + :multiple="multiple" + :query="query" + /> + </div> +</template> + +<script> +import SuitDialog from '@/components/Business/Suit/SuitDialog.vue'; + +export default { + name: 'SuitInput', + components: { SuitDialog }, + props: { + // 选中数据 + value: { + type: [String, Array], + default: null + }, + // 文本 + text: { + type: String, + default: null, + }, + // 是否多选 + multiple: { + type: Boolean, + default: false + }, + // 是否禁用 + disabled: { + type: Boolean, + default: false, + }, + // 查询参数 + query: { + type: Object, + default: () => ({}) + }, + // 打开弹窗前回调 + beforeOpen: { + type: Function, + default: () => { + return true; + } + } + }, + data() { + return { + showDialog: false, + } + }, + methods: { + onOpen() { + if (!this.beforeOpen()) { + return; + } + this.showDialog = true; + }, + handleConfirm(selection) { + if (this.multiple) { + this.$emit('input', selection.map(item => item.id)); + this.$emit('update:text', selection.map(item => item.name).join(',')); + } else { + this.$emit('input', selection?.id); + this.$emit('update:text', selection?.name); + } + this.$emit('confirm', selection); + } + } +} +</script> \ No newline at end of file diff --git a/src/components/Business/User/UserInput.vue b/src/components/Business/User/UserInput.vue index 2808e2a..3fb7f41 100644 --- a/src/components/Business/User/UserInput.vue +++ b/src/components/Business/User/UserInput.vue @@ -21,6 +21,7 @@ <script> import UserDialog from '@/components/Business/User/UserDialog.vue'; import { UserType } from '@/utils/enums'; +import { isDeepEqual } from '@/utils'; export default { components: { UserDialog }, props: { @@ -62,14 +63,24 @@ export default { }, methods: { handleConfirm(selection) { + let value = null; + let text = null; if (this.multiple) { - this.$emit('input', selection.map(item => item.userId)); - this.$emit('update:text', selection.map(item => item.nickName).join(',')); + value = selection.map(item => item.userId); + text = selection.map(item => item.nickName).join(','); } else { - this.$emit('input', selection?.userId); - this.$emit('update:text', selection?.nickName); + value = selection?.userId; + text = selection?.nickName; } + // 如果值发生变化,则触发 change 事件 + if (!isDeepEqual(this.value, value)) { + this.$emit('change', value); + } + + this.$emit('input', value); + this.$emit('update:text', text); this.$emit('confirm', selection); + } } } diff --git a/src/components/CheckDialog/index.vue b/src/components/CheckDialog/index.vue index 43e15ba..51ebfc5 100644 --- a/src/components/CheckDialog/index.vue +++ b/src/components/CheckDialog/index.vue @@ -122,7 +122,7 @@ export default { customQuery: { type: Object, default: () => ({}) - } + }, }, data() { return { @@ -155,7 +155,7 @@ export default { // 合并自定义查询条件 Object.assign(this.query, this.customQuery); - if (this.multiple) { + if (this.multiple && this.selectedIds != null) { this.selection = [...this.selectedIds]; } else { this.selection = [this.selectedIds]; diff --git a/src/utils/enums.js b/src/utils/enums.js index c813481..b59e43e 100644 --- a/src/utils/enums.js +++ b/src/utils/enums.js @@ -74,4 +74,45 @@ export const SuitRentalUnit = { export const SuitRidingRule = { START: "1", // 起步价 INTERVAL: "2", // 区间计费 -} \ No newline at end of file +} + +// 设备状态 +export const DeviceStatus = { + STORAGE: "0", // 仓库中 + AVAILABLE: "1", // 待骑行 + RESERVED: "2", // 预约中 + IN_USE: "3", // 骑行中 + TEMP_LOCKED: "4", // 临时锁车 + DISPATCHING: "6", // 调度中 + DISABLED: "8", // 禁用 + + + // 允许入仓的设备状态 + canIn() { + return [this.AVAILABLE, this.DISPATCHING, this.DISABLED]; + }, + // 允许出仓的设备状态 + canOut() { + return [this.STORAGE]; + }, + // 允许禁用的设备状态 + canDisable() { + return [this.AVAILABLE, this.DISPATCHING, this.STORAGE]; + }, + // 允许启用的设备状态 + canEnable() { + return [this.DISABLED]; + }, + // 允许管理员开锁的设备状态 + canAdminUnlock() { + return [this.DISPATCHING, this.STORAGE, this.AVAILABLE, this.TEMP_LOCKED]; + }, + // 允许用户开锁的设备状态 + canUserUnlock() { + return [this.IN_USE, this.AVAILABLE, this.TEMP_LOCKED]; + }, + // 允许锁车的设备状态 + canLock() { + return [this.AVAILABLE, this.TEMP_LOCKED, this.DISPATCHING, this.IN_USE]; + }, +} diff --git a/src/views/bst/device/components/DeviceEditDialog.vue b/src/views/bst/device/components/DeviceEditDialog.vue new file mode 100644 index 0000000..0019997 --- /dev/null +++ b/src/views/bst/device/components/DeviceEditDialog.vue @@ -0,0 +1,179 @@ +<template> + <el-dialog + :title="title" + :visible.sync="dialogVisible" + width="500px" + append-to-body + :close-on-click-modal="false" + @open="handleOpen" + > + <el-form ref="form" :model="form" :rules="rules" label-width="80px" v-loading="loading"> + <el-row> + <form-col :span="span" label="MAC" prop="mac"> + <el-input v-model="form.mac" placeholder="请输入设备Mac号" :disabled="form.id != null"/> + </form-col> + <form-col :span="span" label="SN" prop="sn"> + <el-input v-model="form.sn" placeholder="请输入设备SN号" :disabled="form.id != null" /> + </form-col> + <form-col :span="span" label="车牌号" prop="vehicleNum"> + <el-input v-model="form.vehicleNum" placeholder="请输入车牌号" /> + </form-col> + <form-col :span="span" label="车型" prop="modelId"> + <model-remote-select v-model="form.modelId" style="width: 100%;" v-if="!loading" :init-options="initModelOptions" /> + </form-col> + <form-col :span="span" label="所属用户" prop="mchId"> + <user-input v-model="form.mchId" :text.sync="form.mchName" :disabled="!checkPermi(['system:user:list'])"/> + </form-col> + <form-col :span="span" label="运营区" prop="areaId"> + <area-remote-select v-model="form.areaId" style="width: 100%;" :init-options="initAreaOptions" v-if="!loading"/> + </form-col> + </el-row> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </el-dialog> +</template> + +<script> +import { getDevice, addDevice, updateDevice } from "@/api/bst/device"; +import FormCol from "@/components/FormCol/index.vue"; +import UserInput from '@/components/Business/User/UserInput.vue'; +import AreaRemoteSelect from '@/components/Business/Area/AreaRemoteSelect.vue'; +import {RoleKeys} from '@/utils/enums'; +import { mapGetters } from 'vuex'; +import ModelRemoteSelect from '@/components/Business/Model/ModelRemoteSelect.vue'; + +export default { + name: 'DeviceEditDialog', + components: { FormCol, UserInput, AreaRemoteSelect, ModelRemoteSelect }, + dicts: ['device_status', 'device_lock_status', 'device_iot_status', 'device_online_status'], + props: { + visible: { + type: Boolean, + default: false + }, + id: { + type: [String, Number], + default: null + }, + initData: { + type: Object, + default: () => ({}) + } + }, + data() { + return { + RoleKeys, + loading: false, + span: 24, + title: '', + form: {}, + rules: { + mac: [ + { required: true, message: "设备Mac号不能为空", trigger: "blur" } + ], + sn: [ + { required: true, message: "设备SN号不能为空", trigger: "blur" } + ], + } + } + }, + computed: { + ...mapGetters(['userId', 'nickName']), + dialogVisible: { + get() { + return this.visible; + }, + set(val) { + this.$emit('update:visible', val); + } + }, + initAreaOptions() { + return [{id: this.form.areaId, name: this.form.areaName}] + }, + initModelOptions() { + return [{id: this.form.modelId, name: this.form.modelName}] + } + }, + methods: { + handleOpen() { + if (this.id == null) { + this.reset(); + this.title = "添加设备"; + } else { + this.getDetail(); + this.title = "修改设备"; + } + }, + reset() { + this.form = { + id: null, + modelId: null, + picture: null, + deviceName: null, + mac: null, + sn: null, + vehicleNum: null, + areaId: null, + activationTime: null, + onlineStatus: null, + createTime: null, + updateTime: null, + remark: null, + status: null, + lockStatus: null, + location: null, + remainingPower: null, + voltage: null, + longitude: null, + latitude: null, + lastTime: null, + version: null, + signalStrength: null, + quality: null, + satellites: null, + gps: null, + lastLocationTime: null, + hardwareVersionId: null, + mchId: null, + iotStatus: null, + isSound: null, + ...this.initData + }; + this.$nextTick(() => { + this.$refs.form && this.$refs.form.clearValidate(); + }); + }, + getDetail() { + this.loading = true; + getDevice(this.id).then(response => { + this.form = response.data; + }).finally(() => { + this.loading = false; + }); + }, + submitForm() { + this.$refs.form.validate(valid => { + if (valid) { + const promise = this.form.id != null ? updateDevice(this.form) : addDevice(this.form); + promise.then(response => { + this.$modal.msgSuccess(this.form.id != null ? "修改成功" : "新增成功"); + this.dialogVisible = false; + this.$emit('success'); + }); + } + }); + }, + cancel() { + this.dialogVisible = false; + this.reset(); + } + } +} +</script> + +<style lang="scss" scoped> + +</style> \ No newline at end of file diff --git a/src/views/bst/device/index.vue b/src/views/bst/device/index.vue new file mode 100644 index 0000000..fa28a2a --- /dev/null +++ b/src/views/bst/device/index.vue @@ -0,0 +1,696 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> + <el-form-item label="SN" prop="sn"> + <el-input + v-model="queryParams.sn" + placeholder="请输入设备SN号" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="MAC" prop="mac"> + <el-input + v-model="queryParams.mac" + placeholder="请输入MAC号" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="设备名称" prop="deviceName"> + <el-input + v-model="queryParams.deviceName" + placeholder="请输入设备名称" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="型号" prop="modelName"> + <el-input + v-model="queryParams.modelName" + placeholder="请输入型号名称" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="车牌号" prop="vehicleNum"> + <el-input + v-model="queryParams.vehicleNum" + placeholder="请输入车牌号" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="运营区" prop="areaId"> + <el-input + v-model="queryParams.areaName" + placeholder="请输入运营区名称" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="在线状态" prop="onlineStatus"> + <el-select v-model="queryParams.onlineStatus" placeholder="请选择在线状态" clearable @change="handleQuery"> + <el-option + v-for="dict in dict.type.device_online_status" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="车辆状态" prop="status"> + <el-select v-model="queryParams.status" placeholder="请选择车辆状态" clearable @change="handleQuery"> + <el-option + v-for="dict in dict.type.device_status" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="锁状态" prop="lockStatus"> + <el-select v-model="queryParams.lockStatus" placeholder="请选择锁状态" clearable @change="handleQuery"> + <el-option + v-for="dict in dict.type.device_lock_status" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="运营商" prop="mchName"> + <el-input + v-model="queryParams.mchName" + placeholder="请输入运营商" + clearable + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="物联网状态" prop="iotStatus" label-width="6em"> + <el-select v-model="queryParams.iotStatus" placeholder="请选择物联网状态" clearable @change="handleQuery"> + <el-option + v-for="dict in dict.type.device_iot_status" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="el-icon-plus" + size="mini" + @click="handleAdd" + v-has-permi="['bst:device:add']" + >新增</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="danger" + plain + icon="el-icon-delete" + size="mini" + :disabled="multiple" + @click="handleDelete" + v-has-permi="['bst:device:remove']" + >删除</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="warning" + plain + icon="el-icon-download" + size="mini" + @click="handleExport" + v-has-permi="['bst:device:export']" + >导出</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="el-icon-upload" + size="mini" + @click="handleOut" + :disabled="multiple" + v-has-permi="['bst:device:out']" + >一键出仓</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="el-icon-download" + size="mini" + @click="handleIn" + :disabled="multiple" + v-has-permi="['bst:device:in']" + >一键入仓</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="danger" + plain + icon="el-icon-close" + size="mini" + @click="handleDisable" + :disabled="multiple" + v-has-permi="['bst:device:disable']" + >一键禁用</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="success" + plain + icon="el-icon-check" + size="mini" + @click="handleEnable" + :disabled="multiple" + v-has-permi="['bst:device:enable']" + >一键启用</el-button> + </el-col> + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList(true)" :columns="columns"></right-toolbar> + </el-row> + + <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="onSortChange"> + <el-table-column type="selection" width="55" align="center" /> + <template v-for="column of showColumns"> + <el-table-column + :key="column.key" + :label="column.label" + :prop="column.key" + :align="column.align" + :min-width="column.minWidth" + :sort-orders="orderSorts" + :sortable="column.sortable" + :show-overflow-tooltip="column.overflow" + :width="column.width" + > + <template slot-scope="d"> + <template v-if="column.key === 'id'"> + {{d.row[column.key]}} + </template> + <template v-else-if="column.key === 'sn'"> + {{d.row.sn | dv}} + <dict-tag :options="dict.type.device_online_status" :value="d.row.onlineStatus" size="mini"/> + <dict-tag :options="dict.type.device_status" :value="d.row.status" size="mini" style="margin-left: 4px;"/> + </template> + <template v-else-if="column.key === 'lockStatus'"> + <dict-tag :options="dict.type.device_lock_status" :value="d.row[column.key]" size="mini"/> + </template> + <template v-else-if="column.key === 'iotStatus'"> + <dict-tag :options="dict.type.device_iot_status" :value="d.row[column.key]" size="mini"/> + </template> + <template v-else-if="column.key === 'quality'"> + <dict-tag :options="dict.type.device_quality" :value="d.row[column.key]" size="mini"/> + </template> + <template v-else-if="column.key === 'remainingPower'"> + {{d.row.remainingPower | fix2 | dv}} % + </template> + <template v-else-if="column.key === 'voltage'"> + {{d.row.voltage | fix2 | dv}} V + </template> + <template v-else-if="column.key === 'isSound'"> + <boolean-tag :value="d.row[column.key]" size="mini" true-text="有声" false-text="静音"/> + </template> + <template v-else> + {{d.row[column.key]}} + </template> + </template> + </el-table-column> + </template> + <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="300"> + <template slot-scope="scope"> + <el-button + size="mini" + type="text" + icon="el-icon-edit" + @click="handleUpdate(scope.row)" + v-has-permi="['bst:device:edit']" + >修改</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-upload" + @click="handleOut(scope.row)" + v-has-permi="['bst:device:out']" + v-show="DeviceStatus.canOut().includes(scope.row.status)" + >出仓</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-download" + @click="handleIn(scope.row)" + v-has-permi="['bst:device:in']" + v-show="DeviceStatus.canIn().includes(scope.row.status)" + >入仓</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-close" + @click="handleDisable(scope.row)" + v-has-permi="['bst:device:disable']" + v-show="DeviceStatus.canDisable().includes(scope.row.status)" + >禁用</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-check" + @click="handleEnable(scope.row)" + v-has-permi="['bst:device:enable']" + v-show="DeviceStatus.canEnable().includes(scope.row.status)" + >启用</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-unlock" + @click="handleUnlock(scope.row)" + v-has-permi="['bst:device:unlock']" + v-show="DeviceStatus.canAdminUnlock().includes(scope.row.status)" + >开锁</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-lock" + @click="handleLock(scope.row)" + v-has-permi="['bst:device:lock']" + v-show="DeviceStatus.canLock().includes(scope.row.status)" + >锁车</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-bell" + @click="handleRing(scope.row)" + v-has-permi="['bst:device:ring']" + >响铃</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-refresh" + @click="handleReboot(scope.row)" + v-has-permi="['bst:device:reboot']" + >重启</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-unlock" + @click="handleUnlockSeat(scope.row)" + v-has-permi="['bst:device:unlockSeat']" + >开坐垫锁</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-refresh" + @click="handleRefresh(scope.row)" + v-has-permi="['bst:device:refresh']" + >刷新</el-button> + <el-button + size="mini" + type="text" + icon="el-icon-delete" + @click="handleDelete(scope.row)" + v-has-permi="['bst:device:remove']" + >删除</el-button> + </template> + </el-table-column> + </el-table> + + <pagination + v-show="total>0" + :total="total" + :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" + @pagination="getList(true)" + /> + + <!-- 添加或修改设备对话框 --> + <device-edit-dialog + :visible.sync="open" + :id="editId" + @success="getList(true)" + /> + </div> +</template> + +<script> +import { listDevice, delDevice, inDevice, outDevice, disableDevice, enableDevice} from "@/api/bst/device"; +import { unlockDevice, lockDevice, ringDevice, rebootDevice, unlockSeatDevice, refreshDevice} from "@/api/bst/deviceIot"; +import { $showColumns } from '@/utils/mixins'; +import FormCol from "@/components/FormCol/index.vue"; +import DeviceEditDialog from './components/DeviceEditDialog.vue'; +import BooleanTag from '@/components/BooleanTag/index.vue'; +import { DeviceStatus } from '@/utils/enums'; + + // 默认排序字段 +const defaultSort = { + prop: "createTime", + order: "descending" +} + +export default { + name: "Device", + mixins: [$showColumns], + dicts: ['device_status', 'device_lock_status', 'device_iot_status', 'device_online_status', 'device_quality'], + components: {FormCol, DeviceEditDialog, BooleanTag}, + data() { + return { + DeviceStatus, + span: 24, + // 字段列表 + columns: [ + {key: 'id', visible: false, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"}, + {key: 'sn', visible: true, label: 'SN', minWidth: null, sortable: true, overflow: false, align: 'left', width: "180"}, + {key: 'mac', visible: true, label: 'MAC', minWidth: "100", sortable: true, overflow: false, align: 'center', width: null}, + {key: 'vehicleNum', visible: true, label: '车牌', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'mchName', visible: true, label: '用户', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'areaName', visible: true, label: '运营区', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'modelName', visible: true, label: '型号', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'signalStrength', visible: true, label: '信号', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'satellites', visible: true, label: '卫星', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'quality', visible: true, label: '电门', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'lockStatus', visible: true, label: '锁', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'voltage', visible: true, label: '电压', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'remainingPower', visible: true, label: '电量', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'isSound', visible: true, label: '声音', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'remark', visible: true, label: '备注', minWidth: null, sortable: true, overflow: true, align: 'center', width: null}, + ], + // 排序方式 + orderSorts: ['ascending', 'descending', null], + // 遮罩层 + loading: true, + // 选中数组 + ids: [], + // 非单个禁用 + single: true, + // 非多个禁用 + multiple: true, + // 显示搜索条件 + showSearch: true, + // 总条数 + total: 0, + // 设备表格数据 + deviceList: [], + // 是否显示弹出层 + open: false, + // 编辑ID + editId: null, + defaultSort, + // 查询参数 + queryParams: { + pageNum: 1, + pageSize: 20, + orderByColumn: defaultSort.prop, + isAsc: defaultSort.order, + refresh: true, + id: null, + modelId: null, + deviceName: null, + mac: null, + sn: null, + vehicleNum: null, + areaId: null, + onlineStatus: null, + remark: null, + status: null, + lockStatus: null, + location: null, + gps: null, + lastLocationTime: null, + hardwareVersionId: null, + mchId: null, + iotStatus: null, + isSound: null + }, + // 表单参数 + form: {}, + // 表单校验 + rules: { + modelId: [ + { required: true, message: "型号id不能为空", trigger: "blur" } + ], + mac: [ + { required: true, message: "设备Mac号不能为空", trigger: "blur" } + ], + sn: [ + { required: true, message: "设备SN号不能为空", trigger: "blur" } + ], + createTime: [ + { required: true, message: "创建时间不能为空", trigger: "blur" } + ], + } + }; + }, + created() { + this.getList(true); + }, + methods: { + // 管理员开锁 + handleUnlock(row) { + this.$confirm('是否确认操作设备【' + row.sn + '】开锁?', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + unlockDevice({ id: row.id }).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,设备已开锁"); + this.getList(true); + } + }) + }) + }, + // 管理员锁车 + handleLock(row) { + this.$confirm('是否确认操作设备【' + row.sn + '】锁车?', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + lockDevice({ id: row.id }).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,设备已锁车"); + this.getList(true); + } + }) + }) + }, + // 管理员响铃寻车 + handleRing(row) { + this.$confirm('是否确认操作设备【' + row.sn + '】响铃寻车?', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + ringDevice({ id: row.id }).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,设备已响铃"); + this.getList(true); + } + }) + }) + }, + // 管理员重启 + handleReboot(row) { + this.$confirm('是否确认操作设备【' + row.sn + '】重启?', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + rebootDevice({ id: row.id }).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,设备已重启"); + this.getList(true); + } + }) + }) + }, + // 管理员开坐垫锁 + handleUnlockSeat(row) { + this.$confirm('是否确认操作设备【' + row.sn + '】开坐垫锁?', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + unlockSeatDevice({ id: row.id }).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,坐垫锁已开"); + this.getList(true); + } + }) + }) + }, + // 管理员刷新 + handleRefresh(row) { + this.$confirm('是否确认刷新设备【' + row.sn + '】?', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + refreshDevice({ id: row.id }).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,设备已刷新"); + this.getList(false); + } + }) + }) + }, + // 一键入仓 + handleOut(row) { + let msg = '是否确认一键出仓?'; + let ids = this.ids; + if (row != null) { + ids = [row.id]; + msg = '是否确认出仓设备【' + row.sn + '】?'; + } + this.$confirm(msg, { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + outDevice(ids).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,共出仓" + res.data + "台设备"); + this.getList(true); + } + }) + }) + }, + // 一键出仓 + handleIn(row) { + let msg = '是否确认一键入仓?'; + let ids = this.ids; + if (row != null) { + ids = [row.id]; + msg = '是否确认入仓设备【' + row.sn + '】?'; + } + this.$confirm(msg, { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + inDevice(ids).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,共入仓" + res.data + "台设备"); + this.getList(true); + } + }) + }) + }, + // 一键禁用 + handleDisable(row) { + let msg = '是否确认一键禁用?'; + let ids = this.ids; + if (row != null) { + ids = [row.id]; + msg = '是否确认禁用设备【' + row.sn + '】?'; + } + this.$confirm(msg, { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + disableDevice(ids).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,共禁用" + res.data + "台设备"); + this.getList(true); + } + }) + }) + }, + // 一键启用 + handleEnable(row) { + let msg = '是否确认一键启用?'; + let ids = this.ids; + if (row != null) { + ids = [row.id]; + msg = '是否确认启用设备【' + row.sn + '】?'; + } + this.$confirm(msg, { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + enableDevice(ids).then((res) => { + if (res.code === 200) { + this.$message.success("操作成功,共启用" + res.data + "台设备"); + this.getList(); + } + }) + }) + }, + /** 当排序按钮被点击时触发 **/ + onSortChange(column) { + if (column.order == null) { + this.queryParams.orderByColumn = defaultSort.prop; + this.queryParams.isAsc = defaultSort.order; + } else { + this.queryParams.orderByColumn = column.prop; + this.queryParams.isAsc = column.order; + } + this.getList(); + }, + /** 查询设备列表 */ + getList(refresh = false) { + this.loading = true; + this.queryParams.refresh = refresh; + listDevice(this.queryParams).then(response => { + this.deviceList = response.rows; + this.total = response.total; + this.loading = false; + }); + }, + /** 搜索按钮操作 */ + handleQuery() { + this.queryParams.pageNum = 1; + this.getList(true); + }, + /** 重置按钮操作 */ + resetQuery() { + this.resetForm("queryForm"); + this.handleQuery(); + }, + // 多选框选中数据 + handleSelectionChange(selection) { + this.ids = selection.map(item => item.id) + this.single = selection.length!==1 + this.multiple = !selection.length + }, + /** 新增按钮操作 */ + handleAdd() { + this.editId = null; + this.open = true; + }, + /** 修改按钮操作 */ + handleUpdate(row) { + this.editId = row.id || this.ids; + this.open = true; + }, + /** 删除按钮操作 */ + handleDelete(row) { + const ids = row.id || this.ids; + this.$modal.confirm('是否确认删除设备编号为"' + ids + '"的数据项?').then(function() { + return delDevice(ids); + }).then(() => { + this.getList(true); + this.$modal.msgSuccess("删除成功"); + }).catch(() => {}); + }, + /** 导出按钮操作 */ + handleExport() { + this.download('bst/device/export', { + ...this.queryParams + }, `device_${new Date().getTime()}.xlsx`) + } + } +}; +</script> diff --git a/src/views/bst/model/components/ModelEditDialog.vue b/src/views/bst/model/components/ModelEditDialog.vue new file mode 100644 index 0000000..ff94822 --- /dev/null +++ b/src/views/bst/model/components/ModelEditDialog.vue @@ -0,0 +1,228 @@ +<template> + <el-dialog + :title="title" + :visible.sync="dialogVisible" + width="500px" + append-to-body + :close-on-click-modal="false" + @open="handleOpen" + > + <el-form ref="form" :model="form" :rules="rules" label-width="80px" size="small"> + <el-row> + <form-col :span="span" label="车型名称" prop="name"> + <el-input v-model="form.name" placeholder="请输入车型名称" /> + </form-col> + <form-col :span="span" label="所属用户" prop="userId"> + <user-input + v-model="form.userId" + :text.sync="form.userName" + :disabled="!checkRole([RoleKeys.ADMIN])" + @change="handleChangeUser" + /> + </form-col> + <form-col :span="span" label="满电电压" prop="fullVoltage"> + <el-input v-model="form.fullVoltage" placeholder="请输入满电电压" type="number"> + <template slot="append">V</template> + </el-input> + </form-col> + <form-col :span="span" label="亏电电压" prop="lowVoltage"> + <el-input v-model="form.lowVoltage" placeholder="请输入亏电电压" type="number"> + <template slot="append">V</template> + </el-input> + </form-col> + <form-col :span="span" label="满电续航" prop="fullEndurance"> + <el-input v-model="form.fullEndurance" placeholder="请输入满电续航" type="number"> + <template slot="append">KM</template> + </el-input> + </form-col> + <form-col :span="span" label="备注" prop="remark"> + <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> + </form-col> + <form-col :span="span" label="低电量提醒开关" prop="lowBatteryReminderSwitch" label-width="9em"> + <el-switch v-model="form.lowBatteryReminderSwitch" /> + </form-col> + <form-col :span="span" label="骑行低电量提醒" prop="lowBatteryReminder" label-width="9em" v-if="form.lowBatteryReminderSwitch"> + <el-input v-model="form.lowBatteryReminder" placeholder="请输入骑行低电量提醒" type="number"> + <template slot="append">%</template> + </el-input> + </form-col> + <form-col :span="span" label="套餐" prop="suitIds"> + <suit-input + v-model="form.suitIds" + :text="suitNames" + multiple + :query="suitQuery" + :before-open="beforeOpenSuit" + /> + </form-col> + </el-row> + </el-form> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </el-dialog> +</template> + +<script> +import { getModel, addModel, updateModel } from "@/api/bst/model"; +import FormCol from "@/components/FormCol/index.vue"; +import UserInput from '@/components/Business/User/UserInput.vue'; +import AreaRemoteSelect from '@/components/Business/Area/AreaRemoteSelect.vue'; +import { RoleKeys } from '@/utils/enums'; +import SuitInput from '@/components/Business/Suit/SuitInput.vue'; +import { mapGetters } from 'vuex'; + +export default { + name: "ModelEditDialog", + components: { + FormCol, + UserInput, + AreaRemoteSelect, + SuitInput + }, + props: { + visible: { + type: Boolean, + default: false + }, + id: { + type: [String, Number], + default: null + }, + initData: { + type: Object, + default: () => ({}) + } + }, + data() { + return { + RoleKeys, + span: 24, + title: '', + form: {}, + rules: { + areaId: [ + { required: true, message: "运营区不能为空", trigger: "change" } + ], + userId: [ + { required: true, message: "运营商不能为空", trigger: "change" } + ], + name: [ + { required: true, message: "车型名称不能为空", trigger: "blur" } + ], + fullVoltage: [ + { required: true, message: "满电电压不能为空", trigger: "blur" } + ], + lowVoltage: [ + { required: true, message: "亏电电压不能为空", trigger: "blur" } + ], + fullEndurance: [ + { required: true, message: "满电续航不能为空", trigger: "blur" } + ], + lowBatteryReminderSwitch: [ + { required: true, message: "低电量提醒开关不能为空", trigger: "blur" } + ], + lowBatteryReminder: [ + { required: true, message: "骑行低电量提醒值不能为空", trigger: "blur" } + ] + } + } + }, + computed: { + ...mapGetters(['userId']), + dialogVisible: { + get() { + return this.visible; + }, + set(val) { + this.$emit('update:visible', val); + } + }, + // 套餐查询条件 + suitQuery() { + return { + userId: this.form.userId + } + }, + suitNames() { + return + } + }, + methods: { + handleChangeUser() { + if (this.form.suitIds != null && this.form.suitIds.length > 0) { + this.form.suitIds = []; + this.form.suitNames = null; + this.$message.warning("由于更换了所属用户,套餐数据已清空"); + } + }, + beforeOpenSuit() { + if (this.form.userId == null) { + this.$modal.msgError("请先选择所属用户"); + return false; + } + return true; + }, + handleOpen() { + if (this.id == null) { + this.reset(); + this.title = "添加车辆型号"; + } else { + this.getDetail(); + this.title = "修改车辆型号"; + } + }, + reset() { + this.form = { + id: null, + areaId: null, + userId: this.userId, + name: null, + fullVoltage: null, + lowVoltage: null, + fullEndurance: null, + createTime: null, + remark: null, + deleted: null, + lowBatteryReminderSwitch: false, + lowBatteryReminder: null, + // dto + suitIds: [], + // vo + suitNames: null, + // 初始化数据 + ...this.initData + }; + this.$nextTick(() => { + this.$refs.form && this.$refs.form.clearValidate(); + }); + }, + getDetail() { + getModel(this.id).then(response => { + this.form = response.data; + }); + }, + submitForm() { + this.$refs.form.validate(valid => { + if (valid) { + const promise = this.form.id != null ? updateModel(this.form) : addModel(this.form); + promise.then(response => { + this.$modal.msgSuccess(this.form.id != null ? "修改成功" : "新增成功"); + this.dialogVisible = false; + this.$emit('success'); + }); + } + }); + }, + cancel() { + this.dialogVisible = false; + this.reset(); + } + } +} +</script> + +<style lang="scss" scoped> + +</style> \ No newline at end of file diff --git a/src/views/bst/model/index.vue b/src/views/bst/model/index.vue index a6b3ff2..c0a49da 100644 --- a/src/views/bst/model/index.vue +++ b/src/views/bst/model/index.vue @@ -17,14 +17,6 @@ @keyup.enter.native="handleQuery" /> </el-form-item> - <el-form-item label="运营区" prop="areaName"> - <el-input - v-model="queryParams.areaName" - placeholder="请输入运营区名称" - clearable - @keyup.enter.native="handleQuery" - /> - </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> @@ -130,65 +122,21 @@ @pagination="getList" /> - <!-- 添加或修改车辆型号对话框 --> - <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false"> - <el-form ref="form" :model="form" :rules="rules" label-width="80px" size="small"> - <el-row> - <form-col :span="span" label="所属用户" prop="userId"> - <user-input v-model="form.userId" :text.sync="form.userName" :disabled="!checkRole([RoleKeys.ADMIN])"/> - </form-col> - <form-col :span="span" label="运营区" prop="areaId"> - <area-remote-select v-model="form.areaId" style="width: 100%;"/> - </form-col> - <form-col :span="span" label="车型名称" prop="name"> - <el-input v-model="form.name" placeholder="请输入车型名称" /> - </form-col> - <form-col :span="span" label="满电电压" prop="fullVoltage"> - <el-input v-model="form.fullVoltage" placeholder="请输入满电电压" type="number"> - <template slot="append">V</template> - </el-input> - </form-col> - <form-col :span="span" label="亏电电压" prop="lowVoltage"> - <el-input v-model="form.lowVoltage" placeholder="请输入亏电电压" type="number"> - <template slot="append">V</template> - </el-input> - </form-col> - <form-col :span="span" label="满电续航" prop="fullEndurance"> - <el-input v-model="form.fullEndurance" placeholder="请输入满电续航" type="number"> - <template slot="append">KM</template> - </el-input> - </form-col> - <form-col :span="span" label="备注" prop="remark"> - <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> - </form-col> - <form-col :span="span" label="低电量提醒开关" prop="lowBatteryReminderSwitch" label-width="9em"> - <el-switch v-model="form.lowBatteryReminderSwitch" /> - </form-col> - <form-col :span="span" label="骑行低电量提醒" prop="lowBatteryReminder" label-width="9em" v-if="form.lowBatteryReminderSwitch"> - <el-input v-model="form.lowBatteryReminder" placeholder="请输入骑行低电量提醒" type="number"> - <template slot="append">%</template> - </el-input> - </form-col> - </el-row> - </el-form> - <div slot="footer" class="dialog-footer"> - <el-button type="primary" @click="submitForm">确 定</el-button> - <el-button @click="cancel">取 消</el-button> - </div> - </el-dialog> + <model-edit-dialog + :visible.sync="dialogVisible" + :id="selectedId" + @success="getList" + /> </div> </template> <script> -import { listModel, getModel, delModel, addModel, updateModel } from "@/api/bst/model"; +import { listModel, delModel } from "@/api/bst/model"; import { $showColumns } from '@/utils/mixins'; -import FormCol from "@/components/FormCol/index.vue"; -import UserInput from '@/components/Business/User/UserInput.vue'; import BooleanTag from '@/components/BooleanTag/index.vue'; -import AreaRemoteSelect from '@/components/Business/Area/AreaRemoteSelect.vue'; -import { RoleKeys } from '@/utils/enums'; +import ModelEditDialog from '@/views/bst/model/components/ModelEditDialog.vue'; - // 默认排序字段 +// 默认排序字段 const defaultSort = { prop: "createTime", order: "descending" @@ -197,17 +145,18 @@ const defaultSort = { export default { name: "Model", mixins: [$showColumns], - components: {FormCol, UserInput, BooleanTag, AreaRemoteSelect}, + components: { + BooleanTag, + ModelEditDialog + }, data() { return { - RoleKeys, - span: 24, // 字段列表 columns: [ {key: 'id', visible: false, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"}, {key: 'name', visible: true, label: '名称', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, - {key: 'areaName', visible: true, label: '运营区', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, - {key: 'userName', visible: true, label: '运营商', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + // {key: 'areaName', visible: true, label: '运营区', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'userName', visible: true, label: '所属用户', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, {key: 'fullVoltage', visible: true, label: '满电电压', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, {key: 'lowVoltage', visible: true, label: '亏电电压', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, {key: 'fullEndurance', visible: true, label: '满电续航', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, @@ -231,10 +180,6 @@ export default { total: 0, // 车辆型号表格数据 modelList: [], - // 弹出层标题 - title: "", - // 是否显示弹出层 - open: false, defaultSort, // 查询参数 queryParams: { @@ -249,38 +194,9 @@ export default { deleted: null, lowBatteryReminderSwitch: null, }, - // 表单参数 - form: {}, - // 表单校验 - rules: { - areaId: [ - { required: true, message: "运营区不能为空", trigger: "change" } - ], - userId: [ - { required: true, message: "运营商不能为空", trigger: "change" } - ], - name: [ - { required: true, message: "车型名称不能为空", trigger: "blur" } - ], - fullVoltage: [ - { required: true, message: "满电电压不能为空", trigger: "blur" } - ], - lowVoltage: [ - { required: true, message: "亏电电压不能为空", trigger: "blur" } - ], - fullEndurance: [ - { required: true, message: "满电续航不能为空", trigger: "blur" } - ], - createTime: [ - { required: true, message: "创建时间不能为空", trigger: "blur" } - ], - lowBatteryReminderSwitch: [ - { required: true, message: "低电量提醒开关不能为空", trigger: "blur" } - ], - lowBatteryReminder: [ - { required: true, message: "骑行低电量提醒值不能为空", trigger: "blur" } - ], - } + // 对话框相关 + dialogVisible: false, + selectedId: null }; }, created() { @@ -307,29 +223,6 @@ export default { this.loading = false; }); }, - // 取消按钮 - cancel() { - this.open = false; - this.reset(); - }, - // 表单重置 - reset() { - this.form = { - id: null, - areaId: null, - userId: null, - name: null, - fullVoltage: null, - lowVoltage: null, - fullEndurance: null, - createTime: null, - remark: null, - deleted: null, - lowBatteryReminderSwitch: false, - lowBatteryReminder: null - }; - this.resetForm("form"); - }, /** 搜索按钮操作 */ handleQuery() { this.queryParams.pageNum = 1; @@ -348,39 +241,13 @@ export default { }, /** 新增按钮操作 */ handleAdd() { - this.reset(); - this.open = true; - this.title = "添加车辆型号"; + this.selectedId = null; + this.dialogVisible = true; }, /** 修改按钮操作 */ handleUpdate(row) { - this.reset(); - const id = row.id || this.ids - getModel(id).then(response => { - this.form = response.data; - this.open = true; - this.title = "修改车辆型号"; - }); - }, - /** 提交按钮 */ - submitForm() { - this.$refs["form"].validate(valid => { - if (valid) { - if (this.form.id != null) { - updateModel(this.form).then(response => { - this.$modal.msgSuccess("修改成功"); - this.open = false; - this.getList(); - }); - } else { - addModel(this.form).then(response => { - this.$modal.msgSuccess("新增成功"); - this.open = false; - this.getList(); - }); - } - } - }); + this.selectedId = row.id || this.ids; + this.dialogVisible = true; }, /** 删除按钮操作 */ handleDelete(row) {