| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- <template>
- <div style="display: flex" v-if="step == 1">
- <div style="flex: 3">
- <a-form :form="form">
- <!-- <a-form-model-item
- label="酒店名称"
- :labelCol="labelCol"
- :wrapperCol="wrapperCol"
- prop="layoutId"
- >
- <a-select
- show-search
- placeholder="请选择酒店"
- option-filter-prop="children"
- @change="hotelChange"
- >
- <a-select-option v-for="(item, index) in hotelId" :key="index">
- {{ item.name }}
- </a-select-option>
- </a-select>
- </a-form-model-item> -->
- <a-form-model-item label="楼栋名称" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="layoutId">
- <a-select show-search placeholder="请选择楼栋" v-model="buildingId" option-filter-prop="children"
- @change="onBuildChange">
- <a-select-option v-for="item in buildingTreeData" :key="item.id">
- {{ item.name }}
- </a-select-option>
- </a-select>
- </a-form-model-item>
- <a-form-model-item label="起始层数" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="layoutId">
- <a-input-number placeholder="输入起始层数" v-model="model.floorCount" :min="1" style="width: 120px" />层
- </a-form-model-item>
- <a-form-model-item label="最高层数" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="layoutId">
- <a-input-number placeholder="输入最高层数" v-model="model.floorCountMax" :min="1" style="width: 120px" />层
- </a-form-model-item>
- <a-form-model-item label="每层房间数量" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="layoutId">
- <a-input-number placeholder="输入每层房间数" v-model="model.roomCount" :min="1" style="width: 120px" />间
- </a-form-model-item>
- <a-form-model-item label="设置前缀" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="layoutId">
- <a-input placeholder="输入房号前缀" v-model="model.prefix" />
- </a-form-model-item>
- <a-form-model-item label="尾号排除" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="layoutId">
- <a-checkbox v-model="model.isExpectEnd"> 尾号排除 </a-checkbox>
- <a-input :disabled="!model.isExpectEnd" placeholder="输入排除的其他尾号" v-model="tailNumber" />
- </a-form-model-item>
- <a-button type="primary" @click="genRooms"> 批量生成 </a-button>
- </a-form>
- </div>
- <div style="flex: 7;">
- <div v-if="roomTree.length > 0" style="height: calc(100vh - (52px + 59px + 100px));overflow-y: auto;">
- <div v-for="(item, index) in roomTree" :key="index" style="width: 100%">
- <div style="font-width: 600; font-size: 20px" @click="sele(item)">
- <a-input placeholder="请填写楼层名" v-model="item.name" class="floor-input"></a-input>
- <a-button @click="delFloor(index)" type="danger" shape="circle" size="small" icon="minus"
- style="margin-left: 5px" />
- </div>
- <div style="color:red;" v-if="isExistNames(item.name)">名称已存在</div>
- <div style="display: flex;justify-content: start;margin: 20px;flex-wrap: wrap;">
- <div v-for="(room, indexs) in item.children" :key="indexs" style="width: 15%; margin-top: 10px">
- <input v-model="room.name" style="width: 50%; margin: auto" />
- <a-button @click="delRoom(index, indexs)" type="danger" shape="circle" size="small" icon="minus"
- style="margin-left: 5px" />
- <div style="color:red;" v-if="repeatName(item.children, indexs)">房名重复</div>
- </div>
- </div>
- <div>
- <a-button @click="addRoom(index)" type="primary" shape="circle" size="small" icon="plus"
- style="margin-left: 20px; margin: 0 20px 20px" />
- </div>
- </div>
- </div>
- <div v-else class="empty-tree">
- <a-empty description="请在左侧生成房间" />
- </div>
- <div class="bottom-btns">
- <a-button @click="back">取消</a-button>
- <a-button @click="save" type="primary">保存</a-button>
- </div>
- </div>
- </div>
- <div v-else class="room-layout-settings">
- <div style="flex:1;position: relative;">
- <div class="wait-select-title" style="display: flex; position: absolute;top: 0;width: 98%;">
- <div class="color-title">待配置房间</div>
- <div class="bottom-sele-btn">
- <a-popover placement="topRight" v-if="canMove.can">
- <template slot="content">
- <a-button type="link" v-for="(item, index) in layouts" :key="item.id" @click="moveTo(index)">
- {{ item.name }}
- </a-button>
- </template>
- <template slot="title">
- <span>要移动到的目标房型</span>
- </template>
- <a-button :disabled="false" type="primary">移动到房型({{ canMove.count }})</a-button>
- </a-popover>
- <a-button v-else :disabled="true" type="primary">移动到房型(0)</a-button>
- <a-button :disabled="saveLoading" :loading="saveLoading" @click="back" type="primary">取消</a-button>
- <a-button :disabled="saveLoading" :loading="saveLoading" @click="save" type="primary">保存并查看房间列表</a-button>
- </div>
- </div>
- <div style="flex:1;height: calc(100vh - 180px);overflow-y: auto;">
- <div style="height: 34px;width: 1px;"></div>
- <div v-for="(item, index) in roomTree" :key="index" style="width: 100%; padding-left: 30px">
- <div style="font-width: 600; font-size: 20px" @click="sele(item)">
- {{ item.name }}
- </div>
- <div style="display: flex;justify-content: start;margin: 20px;flex-wrap: wrap;">
- <div v-for="(room, indexs) in item.children" :key="indexs" class="select-room-item"
- :class="[room.checked ? 'checked-room' : '']" @click="room.checked = !room.checked"
- style="width: 80px; margin-top: 10px">
- {{ room.name }}
- </div>
- </div>
- </div>
- </div>
- </div>
- <div style="flex:1;height: calc(100vh - 180px); overflow-y: auto;">
- <div class="layout-rooms-item" v-for="(item, layoutIndex) in layouts" :key="item.id">
- <div class="title-laytou">
- {{ item.name }}
- </div>
- <div class="room-items">
- <div v-for="(element, roomIndex) in item.rooms" :key="element.id" class="layout-room-item">
- {{ element.name }}
- <a-button @click="delLayoutRoom(element, layoutIndex, roomIndex)" type="danger" shape="circle" size="small"
- icon="minus" style="margin-left: 5px" />
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import draggable from "vuedraggable";
- import { buildingTree, saveBatch } from "@/api/roomBuildingApi";
- import { getAllLayouts } from "@/api/roomLayout";
- export default {
- name: "HotelSaasTenantFrontendRoomGen",
- inject: ["closeCurrent"],
- components: {
- draggable,
- },
- data() {
- return {
- floorNames: [],
- saveLoading: false,
- myArray: [
- {
- id: 1,
- name: "12",
- },
- {
- id: 2,
- name: "33",
- },
- ],
- step: 1,
- layouts: [],
- buildingId: undefined,
- buildingTreeData: [],
- hotelId: [{ name: "A酒店" }, { name: "B酒店" }, { name: "C酒店" }],
- labelCol: {
- xs: { span: 12 },
- sm: { span: 5 },
- },
- wrapperCol: {
- xs: { span: 10 },
- sm: { span: 16 },
- },
- roomTree: [],
- model: {
- floorCount: 1,
- floorCountMax: 2,
- roomCount: 10,
- prefix: "",
- isExpectEnd: false,
- },
- prefixName: "room",
- roomsFromOneFloor: 6,
- tailNumber: "",
- checkNick: false,
- form: this.$form.createForm(this, { name: "dynamic_rule" }),
- seleShow: "", // 用于切换折叠
- };
- },
- computed: {
- canMove() {
- let canMove = {
- can: false,
- count: 0,
- };
- this.roomTree.forEach((floor) => {
- floor.children.forEach((room) => {
- if (room.checked) {
- (canMove.can = true), canMove.count++;
- }
- });
- });
- return canMove;
- },
- },
- mounted() {
- buildingTree().then((res) => {
- if (res.code == 200) {
- this.buildingTreeData = res.result;
- if (res.result && res.result.length > 0) {
- this.buildingId = res.result[0].id
- }
- }
- });
- getAllLayouts().then((res) => {
- if (res.code == 200) {
- res.result.records.forEach((s) => {
- s["rooms"] = [];
- });
- this.layouts = res.result.records;
- }
- });
- },
- methods: {
- onBuildChange() {
- let bIndex = this.buildingTreeData.findIndex(s => s.id == this.buildingId)
- let currentFloorNames = (this.buildingTreeData[bIndex].children || []).map(s => s.name)
- this.floorNames = currentFloorNames
- // this.roomTree = JSON.parse(JSON.stringify(this.roomTree))
- },
- delLayoutRoom(item, layoutIndex, roomIndex) {
- this.roomTree[item.floorIndex].children.push({
- checked: false,
- name: item.name,
- floorIndex: item.floorIndex
- })
- this.layouts[layoutIndex].rooms.splice(roomIndex, 1)
- },
- moveTo(idx) {
- let roomItems = [];
- let rmvObject = {};
- this.roomTree.forEach((floor, floorIndex) => {
- rmvObject["" + floorIndex] = [];
- floor.children.forEach((room, roomIndex) => {
- if (room.checked) {
- rmvObject["" + floorIndex].push(roomIndex);
- roomItems.push({
- floorIndex: floorIndex,
- floorName: floor.name,
- name: room.name,
- });
- }
- });
- });
- let objKeys = Object.keys(rmvObject);
- objKeys.forEach((item) => {
- if (rmvObject[item].length > 0) {
- rmvObject[item].reverse().forEach((index) => {
- this.roomTree[parseInt(item)].children.splice(index, 1);
- });
- }
- });
- let origItems = JSON.parse(JSON.stringify(this.layouts[idx].rooms));
- origItems = origItems.concat(roomItems);
- this.$set(this.layouts[idx], "rooms", origItems);
- },
- onDrag(e) {
- debugger;
- },
- onRoomSelect(index, subIndex) {
- this.$set(this.roomTree[index].children[subIndex], "checked", true);
- },
- save() {
- let result = [];
- let param = {
- hotelId: null,
- buildId: null,
- children: [],
- };
- let hotelInfo = JSON.parse(localStorage.getItem("storeInfo"));
- if (!this.buildingId) {
- this.$message.error("请选择楼栋");
- return;
- }
- if (this.model.roomCount <= 0) {
- this.$message.error("房间数不正确");
- return;
- }
- let errMsg = '';
- for (let i = 0; i < this.roomTree.length; i++) {
- let s = this.roomTree[i]
- if (this.isExistNames(s.name)) {
- errMsg = '楼层名称有重复';
- break;
- }
- }
- if (errMsg == '') {
- for (let i = 0; i < this.roomTree.length; i++) {
- let s = this.roomTree[i]
- for (let j = 0; j < s.children.length; j++) {
- let room = s.children[j]
- if (!room.name) {
- errMsg = '存在空房名,请填写'
- break
- }
- if (this.repeatName(s.children, j)) {
- errMsg = '存在重复房名'
- break
- }
- }
- if (errMsg) break
- }
- }
- if (errMsg) {
- this.$message.error(errMsg)
- return
- }
- if (this.step == 1) {
- this.step = 2;
- return;
- }
- let treeData = this.getParams();
- this.saveLoading = true
- saveBatch(treeData).then(res => {
- if (res.code == 200) {
- this.$message.success("批量保存成功")
- this.closeCurrent()
- }
- }).finally(_ => {
- this.saveLoading = false
- })
- },
- getParams() {
- let param = {
- hotelId: null,
- buildId: null,
- children: [],
- };
- let hotelInfo = JSON.parse(localStorage.getItem("storeInfo"));
- param.buildId = this.buildingId;
- param.hotelId = hotelInfo.id;
- let roomTree = JSON.parse(JSON.stringify(this.roomTree))
- roomTree.forEach(a => {
- param.children.push({
- floorName: a.name,
- children: []
- })
- })
- this.layouts.forEach(layout => {
- layout.rooms.forEach(room => {
- param.children[room.floorIndex].children.push({
- hotelId: hotelInfo.id,
- buildId: this.buildingId,
- layoutId: layout.id,
- name: room.name,
- prefix: this.model.prefix,
- })
- })
- })
- return param
- },
- addRoom(index) {
- this.roomTree[index].children.push({
- name: "",
- floorIndex: index,
- checked: false,
- });
- },
- delFloor(index) {
- this.roomTree.splice(index, 1);
- },
- delRoom(index, roomIndex) {
- this.roomTree[index].children.splice(roomIndex, 1);
- },
- hotelChange(value) {
- console.log(`selected ${value}`);
- },
- tailNumberExclude() {
- console.log(`selected ${value}`);
- },
- sele(data) {
- data.show = !data.show;
- },
- back() {
- this.closeCurrent();
- },
- check() { },
- genRooms() {
- let model = this.model;
- if (!this.buildingId) {
- this.$message.error("请先选择楼栋")
- return
- }
- if (model.floorCount > model.floorCountMax) {
- this.$message.error("最低层数不能大于最高层数")
- return
- }
- let floors = [];
- for (let i = model.floorCount; i <= model.floorCountMax; i++) {
- let children = [];
- for (let r = 0; r < model.roomCount; r++) {
- let expectEndArr = [];
- if (model.isExpectEnd) {
- expectEndArr = (this.tailNumber || "").split(",");
- }
- let numStr = (r + 1).toString();
- let lastChar = numStr[numStr.length - 1];
- if (!expectEndArr.includes(lastChar)) {
- children.push({
- checked: false,
- floorIndex: i,
- name:
- + (i).toString() +
- "0" +
- numStr.padStart(this.model.roomCount.toString().length, "0"),
- });
- }
- }
- floors.push({
- name: `第${i}层`,
- children: children,
- });
- }
- this.roomTree = floors;
- let bIndex = this.buildingTreeData.findIndex(s => s.id == this.buildingId)
- let currentFloorNames = (this.buildingTreeData[bIndex].children || []).map(s => s.name)
- this.floorNames = currentFloorNames
- },
- isExistNames(name) {
- return this.floorNames.includes(name)
- },
- repeatName(items, index) {
- let name = items[index].name
- let newArr = JSON.parse(JSON.stringify(items)).map(s => s.name)
- newArr.splice(index, 1)
- if (newArr.includes(items[index].name)) {
- return true
- }
- return false
- }
- },
- };
- </script>
- <style lang="css" scoped>
- .empty-tree {
- width: 100%;
- height: 300px;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .bottom-btns {
- display: flex;
- justify-content: center;
- margin-bottom: 20px;
- }
- .floor-input {
- width: 200px;
- }
- .room-items {
- display: inline-block;
- border: 1px solid #cccccc77;
- height: 200px;
- overflow-y: auto;
- width: 90%;
- border-radius: 10px;
- margin-bottom: 30px;
- }
- .title-laytou {
- font-size: 17px;
- font-weight: bold;
- width: 100px;
- text-align: center;
- height: 25px;
- line-height: 25px;
- background-color: antiquewhite;
- }
- .room-items-dr {
- border: 1px solid #f00 !important;
- }
- .wait-select-title {
- border-bottom: 4px solid #1cb1ac;
- }
- .color-title {
- background-color: #1cb1ac;
- color: white;
- width: 100px;
- height: 30px;
- line-height: 30px;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- text-align: center;
- }
- .select-room-item {
- border: 1px solid #cccccc77;
- border-radius: 4px;
- margin-right: 4px;
- height: 80px;
- text-align: center;
- line-height: 80px;
- background-color: white;
- cursor: pointer;
- }
- .checked-room {
- background-color: #1cb1ac !important;
- color: white !important;
- border: none !important;
- }
- .bottom-sele-btn {
- height: 30px;
- }
- .layout-room-item {
- display: inline-block;
- width: fit-content;
- padding: 10px 12px;
- }
- .room-layout-settings {
- display: flex;
- }
- </style>
|