qh лет назад: 2
Родитель
Сommit
6ba6cc1931

+ 53 - 0
src/api/roomLayoutPrice.js

@@ -16,4 +16,57 @@ export function list(parameter) {
 }
 
 
+/**
+ * 更新房型价格
+ * @param {object} parameter 参数
+ * @returns Axios Promise
+ */
+ export function modify(parameter) {
+    return axios({
+        url: '/rooms/cesRoomLayoutPrice/modify',
+        method: 'post',
+        data: parameter
+    })
+}
+
+/**
+ * 新增房型价格
+ * @param {object} parameter 参数
+ * @returns Axios Promise
+ */
+ export function create(parameter) {
+    return axios({
+        url: '/rooms/cesRoomLayoutPrice/create',
+        method: 'post',
+        data: parameter
+    })
+}
+
+/**
+ * 获取配置过的房型价格会员等级折扣
+ * @param {object} parameter 
+ * @returns 
+ */
+export function getLayoutpriceLevels(parameter) {
+    return axios({
+        url: '/rooms/cesRoomLayoutMemberPrice/getListByParentId',
+        method: 'get',
+        params: parameter
+    })
+}
+
+
+
+/**
+ * 获取钟点房计费规则
+ * @param {object} parameter 
+ * @returns 
+ */
+ export function getHourRoomRule(parameter) {
+    return axios({
+        url: '/rooms/cesHourRoomRule/list',
+        method: 'get',
+        params: parameter
+    })
+}
 

+ 0 - 1
src/utils/excloudHotelIdParamPath/CesRoomLayoutPriceController.js

@@ -1,7 +1,6 @@
 export default {
     name: '房价管理模块',
     excloudUrls: [
-        '/rooms/cesRoomLayoutPrice/list',
         '/sys/randomImage'
     ]
 }

+ 53 - 0
src/views/settings/components/roomModules/RoomLayoutFormDetailModal.vue

@@ -0,0 +1,53 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="width"
+    :visible="visible"
+    switchFullscreen
+    @ok="handleOk"
+    :okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
+    @cancel="handleCancel"
+    cancelText="关闭">
+    <bus-market-member-form ref="detailForm" @ok="submitCallback" :disabled="disableSubmit"></bus-market-member-form>
+  </j-modal>
+</template>
+
+<script>
+
+  import BusMarketMemberForm from './roomLayoutDetailForm'
+  export default {
+    name: 'BusMarketMemberDetailModal',
+    components: {
+      BusMarketMemberForm
+    },
+    data () {
+      return {
+        title:'详细设置',
+        raw: null,
+        width:800,
+        visible: false,
+        disableSubmit: false
+      }
+    },
+    methods: {
+      setRaw(item) {
+        this.$nextTick(()=>{
+          setTimeout(()=>{
+            this.$refs.detailForm.setRaw(item)
+          },500)
+          
+        });
+        },
+        handleOk() {
+
+        },
+        handleCancel() {
+          this.visible = false
+
+        },
+        submitCallback() {
+          
+        }
+    }
+  }
+</script>

+ 23 - 17
src/views/settings/components/roomModules/RoomLayoutPriceModal.vue

@@ -1,28 +1,31 @@
 <template>
-    <j-modal :title="raw ? ('[' + raw.name + ']-->房价管理') : '房价管理'" :width="width" :visible="visible" switchFullscreen @ok="handleOk"
-        :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
-        <a-tabs
-        default-active-key="1"
-        tab-position="left"
-      >
-        <a-tab-pane  tab="全天房" key="1">
-            <room-qtf-price-table v-if="raw" :layout-id="raw.id"></room-qtf-price-table>
-        </a-tab-pane>
-        <a-tab-pane  tab="钟点房" key="2">
-222
-        </a-tab-pane>
-      </a-tabs>
+    <j-modal :title="raw ? ('[' + raw.name + ']-->房价管理') : '房价管理'" :width="width" :visible="visible" switchFullscreen
+        @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel"
+        cancelText="关闭">
+        <a-tabs default-active-key="1" tab-position="left" @change="ontabChange">
+            <a-tab-pane tab="全天房" key="1">
+                <room-qtf-price-table v-if="raw && tabCurrent == '1'" :layout-id="raw.id"></room-qtf-price-table>
+            </a-tab-pane>
+            <a-tab-pane tab="钟点房" key="2">
+                <room-zdf-price-table v-if="raw && tabCurrent == '2'" :layout-id="raw.id"></room-zdf-price-table>
+               
+            </a-tab-pane>
+        </a-tabs>
     </j-modal>
 </template>
 
 <script>
 import RoomQtfPriceTable from './RoomQtfPriceTable.vue';
+import RoomZdfPriceTable from './RoomZdfPriceTable.vue'
+
 export default {
-    components:{
-        RoomQtfPriceTable
+    components: {
+        RoomQtfPriceTable,
+        RoomZdfPriceTable
     },
     data() {
         return {
+            tabCurrent: '1',
             width: '90%',
             visible: false,
             disableSubmit: false,
@@ -31,13 +34,16 @@ export default {
     },
 
     mounted() {
-        
+
     },
 
     methods: {
         handleOk() {
             console.log(1)
         },
+        ontabChange(e) {
+            this.tabCurrent = e
+        },
         handleCancel() {
             this.visible = false
         },
@@ -52,6 +58,6 @@ export default {
 };
 </script>
 
-<style lang="stylus" scoped>
+<style  scoped>
 
 </style>

+ 171 - 50
src/views/settings/components/roomModules/RoomQtfPriceTable.vue

@@ -1,5 +1,5 @@
 <template>
-    <div >
+    <div>
         <a-table :columns="columns" :data-source="data" :pagination="false" :loading="loading">
             <span slot="prepay" slot-scope="text, record, index">
                 <a-switch checked-children="是" un-checked-children="否" :checked="record.prepay"
@@ -26,7 +26,8 @@
                 </a-col>
                 <a-col :span="3">
                     <a-form-model-item label="原价" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="oprice">
-                        <a-input-number style="width:100%;" v-model="model.oprice" :min="1" placeholder="请填写原价" />
+                        <a-input-number style="width:100%;" v-model="model.oprice" :min="1" placeholder="请填写原价"
+                            @change="formVipOpriceChange" />
                     </a-form-model-item>
                 </a-col>
                 <a-col :span="3">
@@ -35,7 +36,7 @@
                     </a-form-model-item>
                 </a-col>
                 <a-col :span="3">
-                    <a-form-model-item label="预付"  prop="prepay">
+                    <a-form-model-item label="预付" prop="prepay">
                         <a-radio-group v-model="model.prepay">
                             <a-radio-button :value="1">
@@ -69,7 +70,10 @@
                     </a-form-model-item>
                 </a-col>
                 <a-col :span="1">
-                    <a-button @click="submitForm" type="primary">保存</a-button>
+                    <a-button :disabled="submitLoading" :loading="submitLoading" @click="submitForm" type="primary">保存</a-button>
+                </a-col>
+                <a-col :span="1">
+                    <a-button :disabled="submitLoading" :loading="submitLoading" @click="clearForm" type="primary">清空</a-button>
                 </a-col>
             </a-row>
         </a-form-model>
@@ -84,13 +88,16 @@
             <div class="config-heads" v-for="item in vipLevels" :key="item.id">
                 <div class="head-item">[{{ item.name }}]</div>
                 <div class="head-item">
-                    <a-input-number style="width:80%;" v-model="model.oprice" :min="0" placeholder="请填写原价" @change="vipOpriceChange($event, item)"/>
+                    <a-input-number style="width:80%;" v-model="model.oprice" :min="0" placeholder="请填写原价"
+                        @change="vipOpriceChange($event, item)" />
                 </div>
                 <div class="head-item">
-                    <a-input-number style="width:80%;" v-model="item.discount" :min="0" placeholder="请填写折扣" @change="vipDiscountChange($event, item)"/>
+                    <a-input-number style="width:80%;" v-model="item.discount" :min="0" placeholder="请填写折扣"
+                        @change="vipDiscountChange($event, item)" />
                 </div>
                 <div class="head-item">
-                    <a-input-number style="width:80%;" :value="item.price" :min="0" placeholder="请填写现价" @change="vipPriceChange($event, item)"/>
+                    <a-input-number style="width:80%;" :value="item.price" :min="0" placeholder="请填写现价"
+                        @change="vipPriceChange($event, item)" />
                 </div>
             </div>
         </div>
@@ -98,9 +105,11 @@
 </template>
 
 <script>
-import { list } from '@/api/roomLayoutPrice'
+import { list, modify, create, getLayoutpriceLevels } from '@/api/roomLayoutPrice'
 import { httpAction, getAction } from "@/api/manage";
 import * as api from '@/api/api'
+import { find } from 'lodash';
+import json5 from 'json5';
 const columns = [
     {
         title: '房价名称',
@@ -152,6 +161,7 @@ export default {
     },
     data() {
         return {
+            submitLoading: false,
             labelCol: {
                 xs: { span: 24 },
                 sm: { span: 10 },
@@ -190,39 +200,65 @@ export default {
     mounted() {
         this.getData()
         this.getVipLevels()
+
     },
     methods: {
+        clearForm() {
+            this.model = {
+                id: '',
+                name: '',
+                oprice: null,
+                price: null,
+                prepay: 0,
+                integral: 0,
+                num: 0,
+                isVip: 0
+            }
+            this.vipLevels = JSON.parse(JSON.stringify(this.origiVipLevels))
+        },
         vipPriceChange(e, item) {
-            if(this.model.oprice) {
+            if (this.model.oprice) {
                 item.discount = ((e / this.model.oprice) * 100).toFixed(2)
             }
             item.price = e
         },
         vipDiscountChange(e, item) {
-            if(this.model.oprice) {
-                item.price = (this.model.oprice * (e/100)).toFixed(2)
+            if (this.model.oprice) {
+                item.price = (this.model.oprice * (e / 100)).toFixed(2)
             }
             item.discount = e
         },
         vipOpriceChange(e, item) {
-            if(item.discount) {
-                item.price = (this.model.oprice * (item.discount/100)).toFixed(2)
+            if (item.discount) {
+                item.price = (this.model.oprice * (item.discount / 100)).toFixed(2)
             }
             this.model.oprice = e
         },
+        formVipOpriceChange(e) {
+            (this.vipLevels || []).forEach(item => {
+                if (item.discount) {
+                    item.price = (this.model.oprice * (item.discount / 100)).toFixed(2)
+                }
+            })
+            this.model.oprice = e
+        },
         getVipLevels() {
             api.getVipLevels({
                 pageNo: 1,
                 pageSize: 999,
                 hotelId: hotelItem.id
             }).then(res => {
-                if(res.result && res.result.records) {
-                    
-                    res.result.records.forEach(s=>{
+                if (res.result && res.result.records) {
+
+                    res.result.records.forEach(s => {
                         s['price'] = 0
-                        if(!s.discount) {
+                        // 保存原有折扣率
+                        s['ldiscount'] = s.discount
+                        if (!s.discount) {
                             s.discount = 100
                         }
+
+
                     })
                     this.origiVipLevels = res.result.records
                     this.vipLevels = JSON.parse(JSON.stringify(res.result.records))
@@ -233,15 +269,48 @@ export default {
 
         },
         onVipChange(e) {
-            if(this.model.isVip) {
+            if (this.model.isVip) {
 
             }
         },
         handleEdit(record) {
-            let cpData = JSON.parse(JSON.stringify(record))
-            cpData.isVip = record.isVip? 1 : 0
-            cpData.prepay = record.prepay? 1 : 0
-            this.model = cpData
+            this.getRelationLevels(record.id, (rLevels) => {
+
+                let cpData = JSON.parse(JSON.stringify(record))
+                cpData.isVip = record.isVip ? 1 : 0
+                cpData.prepay = record.prepay ? 1 : 0
+                this.model = cpData
+                let nowLvs = JSON.parse(JSON.stringify(this.origiVipLevels))
+                if (this.model.oprice) {
+                    nowLvs.forEach(s => {
+                        if (rLevels) {
+                            let findIndex = rLevels.findIndex(q => q.levelId == s.id)
+                            if (findIndex > -1) {
+                                s.discount = rLevels[findIndex].discount
+                                s['memberPriceId'] = rLevels[findIndex].id
+                            } else {
+                                s['memberPriceId'] = ''
+                            }
+                        }
+                        s.price = (this.model.oprice * (s.discount / 100)).toFixed(2)
+                    })
+                }
+                this.vipLevels = nowLvs
+            })
+
+
+        },
+        getRelationLevels(pid, callback) {
+            getLayoutpriceLevels({
+                parentId: pid
+            }).then(res => {
+                // 关联折扣等级
+                let rLevels = []
+                if (res.code == 200 && res.result.length > 0) {
+                    rLevels = res.result
+                }
+                callback(rLevels)
+            })
         },
         getData() {
             this.loading = true
@@ -268,53 +337,105 @@ export default {
             this.$refs.form.validate((valid) => {
                 if (valid) {
                     that.confirmLoading = true;
-                    let httpurl = "";
-                    let method = "";
-                    // if (!this.model.id) {
-                    //     httpurl += this.url.add;
-                    //     method = "post";
-                    // } else {
-                    //     httpurl += this.url.edit;
-                    //     method = "put";
-                    // }
-                    // if (this.model.payFlag == 0) {
-                    //     this.model.payAmount = 0;
-                    // }
-                    // httpAction(httpurl, this.model, method)
-                    //     .then((res) => {
-                    //         if (res.success) {
-                    //             that.$message.success(res.message);
-                    //             that.$emit("ok");
-                    //         } else {
-                    //             that.$message.warning(res.message);
-                    //         }
-                    //     })
-                    //     .finally(() => {
-                    //         that.confirmLoading = false;
-                    //     });
+                    if (this.model.id && this.model.id != '') {
+                        this.doModify()
+                    } else {
+                        this.doCreate()
+                    }
                 }
             });
         },
+        doModify() {
+            let model = JSON.parse(JSON.stringify(this.model))
+            model['hotelId'] = hotelItem.id
+            model['layoutId'] = this.layoutId
+            model['type'] = 1
+
+            let memberPriceEntities = [];
+            if (model.isVip) {
+                (this.vipLevels || []).forEach(s => {
+                    let item = {
+                        id: s.memberPriceId,
+                        levelId: s.id,
+                        discount: parseFloat(s.discount || 100),
+                        ldiscount: parseFloat(s.ldiscount || 100),
+                    }
+                    memberPriceEntities.push(item)
+                })
+            }
+
+            model['memberPriceEntities'] = memberPriceEntities
+
+            this.submitLoading = true
+            modify(model).then(s => {
+                if (s.code == 200) {
+                    this.$message.success("保存成功")
+                    this.clearForm()
+                    this.getData()
+                }
+            }).catch(err => {
+                this.$message.error("保存失败")
+            }).finally(_ => {
+                this.submitLoading = false
+            })
+        },
+        doCreate() {
+            
+            let model = JSON.parse(JSON.stringify(this.model))
+            model['hotelId'] = hotelItem.id
+            model['layoutId'] = this.layoutId
+            model['type'] = 1
+            let memberPriceEntities = [];
+            if (model.isVip) {
+                (this.vipLevels || []).forEach(s => {
+                    let item = {
+                        levelId: s.id,
+                        hotelId: hotelItem.id,
+                        discount: parseFloat(s.discount || 100),
+                        ldiscount: parseFloat(s.ldiscount || 100),
+                    }
+                    memberPriceEntities.push(item)
+                })
+            }
+
+            model['memberPriceEntities'] = memberPriceEntities
+            this.submitLoading = true
+            create(model).then(s => {
+                if (s.code == 200) {
+                    this.$message.success("保存成功")
+                    this.clearForm()
+                    this.getData()
+                }
+            }).catch(err => {
+                this.$message.error("保存失败")
+            }).finally(_ => {
+                
+                this.submitLoading = false
+            })
+        }
 
     },
 };
 </script>
 
 <style lang="css" scoped>
-.vip-config{
+.vip-config {
     width: 30%;
     height: 200px;
     overflow-y: auto;
     margin-top: 20px;
 }
-.config-heads{
+
+.config-heads {
     display: flex;
 }
-.config-heads .head-item{
+
+.config-heads .head-item {
     flex: 1;
     text-align: left;
 }
-.h-title{
+
+.h-title {
     font-weight: 600;
 }
 </style>

+ 561 - 0
src/views/settings/components/roomModules/RoomZdfPriceTable.vue

@@ -0,0 +1,561 @@
+<template>
+    <div>
+        <a-table :columns="columns" :data-source="data" :pagination="false" :loading="loading">
+            <span slot="prepay" slot-scope="text, record, index">
+                <a-switch checked-children="是" un-checked-children="否" :checked="record.prepay"
+                    @change="changePrepay(record)" />
+            </span>
+            <span slot="isVip" slot-scope="text, record, index">
+                <a-switch checked-children="是" un-checked-children="否" :checked="record.isVip" />
+            </span>
+            <span slot="startDate" slot-scope="text, record, index">
+                {{ record.startDate }} ~ {{ record.endDate }}
+            </span>
+            
+            <span slot="sellerId" slot-scope="text, record, index">
+                {{ record.sellerId ? getSellerName(record.sellerId): '' }}
+            </span>
+            <span slot="action" slot-scope="text, record">
+                <a @click="handleEdit(record)">编辑</a>
+
+                <a-divider type="vertical" />
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                    <a>删除</a>
+                </a-popconfirm>
+            </span>
+        </a-table>
+        <a-form-model layout="inline" ref="form" :model="model" :rules="validatorRules" slot="detail">
+            <a-row>
+                <a-col :span="3">
+                    <a-form-model-item label="价格名称" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="name">
+                        <a-input v-model="model.name" placeholder="请输入房价名称"></a-input>
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="原价" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="oprice">
+                        <a-input-number style="width:100%;" v-model="model.oprice" :min="1" placeholder="请填写原价"
+                            @change="formVipOpriceChange" />
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="现价" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="price">
+                        <a-input-number style="width:100%;" v-model="model.price" :min="1" placeholder="请填写现价" />
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="预付" prop="prepay">
+                        <a-radio-group v-model="model.prepay">
+                            <a-radio-button :value="1">
+                                是
+                            </a-radio-button>
+                            <a-radio-button :value="0">
+                                否
+                            </a-radio-button>
+                        </a-radio-group>
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="积分" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="integral">
+                        <a-input-number style="width:100%;" v-model="model.integral" placeholder="请填写积分" />
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="数量" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="num">
+                        <a-input-number style="width:100%;" v-model="model.num" placeholder="请填写数量" />
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="会员折扣" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="isVip">
+                        <a-radio-group v-model="model.isVip" @change="onVipChange">
+                            <a-radio-button :value="1">
+                                是
+                            </a-radio-button>
+                            <a-radio-button :value="0">
+                                否
+                            </a-radio-button>
+                        </a-radio-group>
+                    </a-form-model-item>
+                </a-col>
+                
+            </a-row>
+            <a-row>
+                <a-col :span="4">
+                    <a-form-model-item label="适用时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="startDate">
+                        <a-time-picker :open.sync="open2"  v-model="model.startDate" format="HH:mm" @change="onStartTimeChange">
+                            <a-button slot="addon" size="small" type="primary" @click="open2 = false">
+                              确定
+                            </a-button>
+                          </a-time-picker>
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="3">
+                    <a-form-model-item label="" :labelCol="labelCol1" :wrapperCol="wrapperCol" prop="endDate">
+                        <a-time-picker :open.sync="open" v-model="model.endDate" format="HH:mm">
+                            <a-button slot="addon" size="small" type="primary" @click="open = false">
+                              确定
+                            </a-button>
+                          </a-time-picker>
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="4">
+                    <a-form-model-item label="钟点房方案" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="sellerId">
+                        <a-select style="width: 120px" v-model="model.sellerId" placeholder="请选择">
+                            <a-select-option :value="item.id" v-for="item in hourRules">
+                              {{ item.hourRoomName }}
+                            </a-select-option>
+                          </a-select>
+                    </a-form-model-item>
+                </a-col>
+                <a-col :span="2">
+                    <a-button :disabled="submitLoading" :loading="submitLoading" @click="submitForm" type="primary">保存</a-button>
+                </a-col>
+                <a-col :span="1">
+                    <a-button :disabled="submitLoading" :loading="submitLoading" @click="clearForm" type="primary">清空</a-button>
+                </a-col>
+            </a-row>
+        </a-form-model>
+
+        <div class="vip-config" v-if="model.isVip">
+            <div class="config-heads h-title">
+                <div class="head-item">会员等级</div>
+                <div class="head-item">原价</div>
+                <div class="head-item">折扣(%)</div>
+                <div class="head-item">现价</div>
+            </div>
+            <div class="config-heads" v-for="item in vipLevels" :key="item.id">
+                <div class="head-item">[{{ item.name }}]</div>
+                <div class="head-item">
+                    <a-input-number style="width:80%;" v-model="model.oprice" :min="0" placeholder="请填写原价"
+                        @change="vipOpriceChange($event, item)" />
+                </div>
+                <div class="head-item">
+                    <a-input-number style="width:80%;" v-model="item.discount" :min="0" placeholder="请填写折扣"
+                        @change="vipDiscountChange($event, item)" />
+                </div>
+                <div class="head-item">
+                    <a-input-number style="width:80%;" :value="item.price" :min="0" placeholder="请填写现价"
+                        @change="vipPriceChange($event, item)" />
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+Date.prototype.Format = function (fmt) {
+        var o = {
+        "M+": this.getMonth() + 1, //月份
+        "d+": this.getDate(), //日
+        "H+": this.getHours(), //小时
+        "m+": this.getMinutes(), //分
+        "s+": this.getSeconds(), //秒
+        "q+": Math.floor((this.getMonth() + 3) / 3), //季度
+        "S": this.getMilliseconds() //毫秒
+        };
+        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+        for (var k in o)
+        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+        return fmt;
+        }
+import { list, modify, create, getLayoutpriceLevels, getHourRoomRule } from '@/api/roomLayoutPrice'
+import { httpAction, getAction } from "@/api/manage";
+import * as api from '@/api/api'
+import { find } from 'lodash';
+import moment from 'moment';
+const columns = [
+    {
+        title: '房价名称',
+        dataIndex: 'name',
+        key: 'name',
+    },
+    {
+        title: '原价',
+        dataIndex: 'oprice',
+        key: 'oprice',
+    },
+    {
+        title: '现价',
+        dataIndex: 'price',
+        key: 'price',
+    },
+    {
+        title: '适用时段',
+        key: 'startDate',
+        dataIndex: 'startDate',
+        scopedSlots: { customRender: 'startDate' },
+    },
+    {
+        title: '预付',
+        key: 'prepay',
+        dataIndex: 'prepay',
+        scopedSlots: { customRender: 'prepay' },
+    },
+
+    {
+        title: '积分',
+        dataIndex: 'integral',
+        key: 'integral',
+    },
+    {
+        title: '数量',
+        dataIndex: 'num',
+        key: 'num',
+    },
+    {
+        title: '使用会员折扣',
+        dataIndex: 'isVip',
+        key: 'isVip',
+        scopedSlots: { customRender: 'isVip' },
+    },
+    {
+        title: '钟点房方案',
+        key: 'sellerId',
+        dataIndex: 'sellerId',
+        scopedSlots: { customRender: 'sellerId' },
+    },
+    {
+        title: '操作',
+        key: 'action',
+        scopedSlots: { customRender: 'action' },
+    },
+];
+let hotelItem = JSON.parse(window.localStorage.getItem('storeInfo'))
+export default {
+    props: {
+        layoutId: null
+    },
+    data() {
+        return {
+            open: false,
+            open2: false,
+            submitLoading: false,
+            labelCol1: {
+                xs: { span: 0 },
+                sm: { span: 0 },
+            },
+            labelCol: {
+                xs: { span: 24 },
+                sm: { span: 10 },
+            },
+            wrapperCol: {
+                xs: { span: 24 },
+                sm: { span: 14 },
+            },
+            loading: false,
+            data: [],
+            columns,
+            searchType: 2,
+            validatorRules: {
+                name: [{ required: true, message: "请输入房价名称!" }],
+                oprice: [{ required: true, message: "请填写原价价!" }],
+                price: [{ required: true, message: "请填写现价!" }],
+                startDate: [{ required: true, message: "请选择适用开始时间" }],
+                endDate: [{ required: true, message: "请选择适用结束时间" }],
+                integral: [{ required: true, message: "请填写积分!" }],
+                lunchNum: [{ required: true, message: "请填写中餐数量!" }],
+                dinnerNum: [{ required: true, message: "请填写晚餐数量!" }],
+            },
+            model: {
+                id: '',
+                name: '',
+                oprice: null,
+                price: null,
+                prepay: 0,
+                integral: 0,
+                num: 0,
+                startDate: null,
+                endDate: null,
+                isVip: 0,
+                sellerId: null,
+            },
+            vipLevels: [],
+            origiVipLevels: [],
+            hourRules: []
+        };
+    },
+
+    mounted() {
+        this.getData()
+        this.getVipLevels()
+        this.getHourRoomRule()
+    },
+    methods: {
+        onStartTimeChange(e, timeStr) {
+            console.log(e,timeStr,this.model.startDate)
+        },
+        onEndTimeChange(e, timeStr) {
+            this.model.endDate = timeStr
+        },
+        getSellerName(id) {
+            let index = this.hourRules.findIndex(s=>s.id == id)
+            if(index > -1) {
+                return this.hourRules[index].hourRoomName
+            }
+            return id
+        },
+        clearForm() {
+            this.model = {
+                id: '',
+                name: '',
+                oprice: null,
+                price: null,
+                prepay: 0,
+                integral: 0,
+                startDate: null,
+                endDate: null,
+                sellerId: null,
+                num: 0,
+                isVip: 0
+            }
+            this.vipLevels = JSON.parse(JSON.stringify(this.origiVipLevels))
+        },
+        vipPriceChange(e, item) {
+            if (this.model.oprice) {
+                item.discount = ((e / this.model.oprice) * 100).toFixed(2)
+            }
+            item.price = e
+        },
+        vipDiscountChange(e, item) {
+            if (this.model.oprice) {
+                item.price = (this.model.oprice * (e / 100)).toFixed(2)
+            }
+            item.discount = e
+        },
+        vipOpriceChange(e, item) {
+            if (item.discount) {
+                item.price = (this.model.oprice * (item.discount / 100)).toFixed(2)
+            }
+            this.model.oprice = e
+        },
+        formVipOpriceChange(e) {
+            (this.vipLevels || []).forEach(item => {
+                if (item.discount) {
+                    item.price = (this.model.oprice * (item.discount / 100)).toFixed(2)
+                }
+            })
+            this.model.oprice = e
+        },
+        getHourRoomRule() {
+            getHourRoomRule({
+                pageNo: 1,
+                pageSize: 999
+            }).then(res => {
+                if(res.code == 200) {
+                    this.hourRules = res.result.records
+                } else {
+                    this.$message.warning('⚠️没有找到钟点房方案')
+                }
+            })
+        },
+        getVipLevels() {
+            api.getVipLevels({
+                pageNo: 1,
+                pageSize: 999,
+                hotelId: hotelItem.id
+            }).then(res => {
+                if (res.result && res.result.records) {
+
+                    res.result.records.forEach(s => {
+                        s['price'] = 0
+                        // 保存原有折扣率
+                        s['ldiscount'] = s.discount
+                        if (!s.discount) {
+                            s.discount = 100
+                        }
+
+
+                    })
+                    this.origiVipLevels = res.result.records
+                    this.vipLevels = JSON.parse(JSON.stringify(res.result.records))
+                }
+            })
+        },
+        changePrepay(record) {
+
+        },
+        onVipChange(e) {
+            if (this.model.isVip) {
+
+            }
+        },
+        handleEdit(record) {
+            this.getRelationLevels(record.id, (rLevels) => {
+
+                let cpData = JSON.parse(JSON.stringify(record))
+                cpData.isVip = record.isVip ? 1 : 0
+                cpData.prepay = record.prepay ? 1 : 0
+                this.model = cpData
+                this.model.startDate = moment(this.model.startDate,"HH:mm")
+                this.model.endDate = moment(this.model.endDate,"HH:mm")
+                let nowLvs = JSON.parse(JSON.stringify(this.origiVipLevels))
+                if (this.model.oprice) {
+                    nowLvs.forEach(s => {
+                        if (rLevels) {
+                            let findIndex = rLevels.findIndex(q => q.levelId == s.id)
+                            if (findIndex > -1) {
+                                s.discount = rLevels[findIndex].discount
+                                s['memberPriceId'] = rLevels[findIndex].id
+                            } else {
+                                s['memberPriceId'] = ''
+                            }
+                        }
+                        s.price = (this.model.oprice * (s.discount / 100)).toFixed(2)
+                    })
+                }
+                this.vipLevels = nowLvs
+            })
+
+
+        },
+        getRelationLevels(pid, callback) {
+            getLayoutpriceLevels({
+                parentId: pid
+            }).then(res => {
+                // 关联折扣等级
+                let rLevels = []
+                if (res.code == 200 && res.result.length > 0) {
+                    rLevels = res.result
+                }
+                callback(rLevels)
+            })
+        },
+        getData() {
+            this.loading = true
+            list({
+                type: this.searchType,
+                // hotelId: hotelItem.id,
+                roomLayoutId: this.layoutId,
+                pageNo: 1,
+                pageSize: 999
+            }).then(res => {
+                this.loading = false
+                console.log(res)
+                this.data = res.result.records
+            }).catch(res => {
+                this.loading = false
+            })
+        },
+        handleDelete(id) {
+
+        },
+        submitForm() {
+            const that = this;
+            // 触发表单验证
+            this.$refs.form.validate((valid) => {
+                if (valid) {
+                    that.confirmLoading = true;
+                    if (this.model.id && this.model.id != '') {
+                        this.doModify()
+                    } else {
+                        this.doCreate()
+                    }
+                }
+            });
+        },
+        doModify() {
+            let model = JSON.parse(JSON.stringify(this.model))
+            model['hotelId'] = hotelItem.id
+            model['layoutId'] = this.layoutId
+            model['type'] = 2
+            model.startDate = this.model.startDate
+            model.endDate = this.model.endDate
+            model.startDate =model.startDate.utcOffset(8).format("HH:mm")
+            model.endDate = model.endDate.utcOffset(8).format("HH:mm")
+            let memberPriceEntities = [];
+            if (model.isVip) {
+                (this.vipLevels || []).forEach(s => {
+                    let item = {
+                        id: s.memberPriceId,
+                        levelId: s.id,
+                        discount: parseFloat(s.discount || 100),
+                        ldiscount: parseFloat(s.ldiscount || 100),
+                    }
+                    memberPriceEntities.push(item)
+                })
+            }
+
+            model['memberPriceEntities'] = memberPriceEntities
+
+            this.submitLoading = true
+            modify(model).then(s => {
+                if (s.code == 200) {
+                    this.$message.success("保存成功")
+                    this.clearForm()
+                    this.getData()
+                }
+            }).catch(err => {
+                this.$message.error("保存失败")
+            }).finally(_ => {
+                this.submitLoading = false
+            })
+        },
+        doCreate() {
+            
+            let model = JSON.parse(JSON.stringify(this.model))
+            model['hotelId'] = hotelItem.id
+            model['layoutId'] = this.layoutId
+            model['type'] = 2
+            // 经过序列化的moment要重新赋值成moment对象
+            model.startDate = this.model.startDate
+            model.endDate = this.model.endDate
+            model.startDate =model.startDate.utcOffset(8).format("HH:mm")
+            model.endDate = model.endDate.utcOffset(8).format("HH:mm")
+            let memberPriceEntities = [];
+            
+            if (model.isVip) {
+                (this.vipLevels || []).forEach(s => {
+                    let item = {
+                        levelId: s.id,
+                        hotelId: hotelItem.id,
+                        discount: parseFloat(s.discount || 100),
+                        ldiscount: parseFloat(s.ldiscount || 100),
+                    }
+                    memberPriceEntities.push(item)
+                })
+            }
+
+            model['memberPriceEntities'] = memberPriceEntities
+            this.submitLoading = true
+            create(model).then(s => {
+                if (s.code == 200) {
+                    this.$message.success("保存成功")
+                    this.clearForm()
+                    this.getData()
+                }
+            }).catch(err => {
+                this.$message.error("保存失败")
+            }).finally(_ => {
+                
+                this.submitLoading = false
+            })
+        }
+
+    },
+};
+</script>
+
+<style lang="css" scoped>
+.vip-config {
+    width: 30%;
+    height: 200px;
+    overflow-y: auto;
+    margin-top: 20px;
+}
+
+.config-heads {
+    display: flex;
+}
+
+.config-heads .head-item {
+    flex: 1;
+    text-align: left;
+}
+
+.h-title {
+    font-weight: 600;
+}
+/deep/
+.ant-select-selection__placeholder, .ant-select-search__field__placeholder{
+    display: inline-block !important;
+}
+</style>

+ 165 - 0
src/views/settings/components/roomModules/roomLayoutDetailForm.vue

@@ -0,0 +1,165 @@
+<template>
+    <a-tabs default-active-key="1" @change="()=>{}">
+        <a-tab-pane key="1" tab="房型详情">
+          <detail></detail>
+        </a-tab-pane>
+        <a-tab-pane key="2" tab="设备服务">
+          <device></device>
+        </a-tab-pane>
+        <a-tab-pane key="3" tab="房型图片">
+          <layout-image></layout-image>
+        </a-tab-pane>
+      </a-tabs>
+</template>
+
+<script>
+import { getRoomPlans, getSelectList } from "@/api/api";
+import { httpAction, getAction } from "@/api/manage";
+import { validateDuplicateValue } from "@/utils/util";
+import detail from './roomLayoutDetailForm/roomLayoutDetail.vue'
+import device from './roomLayoutDetailForm/roomLayoutDevice.vue'
+import layoutImage from './roomLayoutDetailForm/roomLayoutImage.vue'
+
+export default {
+    name: "BusMarketMemberForm",
+    props: {
+        disabled: {
+            type: Boolean,
+            default: false,
+            required: false,
+        },
+    },
+    components: {
+        detail,
+        device,
+        layoutImage
+    },
+    data() {
+        return {
+            model: {
+                id: "",
+                hotelId: 0,
+                name: null,
+                marketPrice: null,
+                canLivePersonNum: 0,
+                breakfastNum: 0,
+                lunchNum: 0,
+                dinnerNum: 0
+            },
+            labelCol: {
+                xs: { span: 24 },
+                sm: { span: 5 },
+            },
+            wrapperCol: {
+                xs: { span: 24 },
+                sm: { span: 16 },
+            },
+            confirmLoading: false,
+            validatorRules: {
+                name: [{ required: true, message: "请输入房型!" }],
+                marketPrice: [{ required: true, message: "请填写门市价!" }],
+                canLivePersonNum: [{ required: true, message: "请填写可住人数!" }],
+                breakfastNum: [{ required: true, message: "请填写早餐数量!" }],
+                lunchNum: [{ required: true, message: "请填写中餐数量!" }],
+                dinnerNum: [{ required: true, message: "请填写晚餐数量!" }],
+            },
+            url: {
+                add: "/rooms/cesRoomLayout/save",
+                edit: "/rooms/cesRoomLayout/modify",
+                queryById: "/rooms/cesRoomLayout/queryById",
+            },
+            iconChooseVisible: false,
+            roomPlans: [],
+            members: [],
+        };
+    },
+    computed: {
+        formDisabled() {
+            return this.disabled;
+        },
+    },
+    created() {
+        var _info = JSON.parse(localStorage.getItem("storeInfo"));
+        if (_info) {
+            this.model.hotelId = _info.id;
+            this.initData();
+        }
+        this.modelDefault = JSON.parse(JSON.stringify(this.model));
+    },
+    methods: {
+        setRaw(item) {
+            this.model = JSON.parse(JSON.stringify(item))
+        },
+        initData() {
+            getRoomPlans(this.model.hotelId, null).then((res) => {
+                if (res.success) {
+                    this.roomPlans = res.result;
+                }
+            });
+
+        },
+        selectIcons() {
+            this.iconChooseVisible = true;
+        },
+        handleIconCancel() {
+            this.iconChooseVisible = false;
+        },
+        handleIconChoose(value) {
+            console.log(value);
+            this.model.icon = value;
+            this.iconChooseVisible = false;
+        },
+        add() {
+            this.edit(this.modelDefault);
+        },
+        edit(record) {
+            this.model = Object.assign({}, record);
+            this.visible = true;
+            getSelectList({ id: this.model.id }).then((res) => {
+                if (res.success) {
+                    this.members = res.result;
+                }
+            });
+        },
+        submitForm() {
+            const that = this;
+            // 触发表单验证
+            this.$refs.form.validate((valid) => {
+                if (valid) {
+                    that.confirmLoading = true;
+                    let httpurl = "";
+                    let method = "";
+                    if (!this.model.id) {
+                        httpurl += this.url.add;
+                        method = "post";
+                    } else {
+                        httpurl += this.url.edit;
+                        method = "put";
+                    }
+                    if (this.model.payFlag == 0) {
+                        this.model.payAmount = 0;
+                    }
+                    httpAction(httpurl, this.model, method)
+                        .then((res) => {
+                            if (res.success) {
+                                that.$message.success(res.message);
+                                that.$emit("ok");
+                            } else {
+                                that.$message.warning(res.message);
+                            }
+                        })
+                        .finally(() => {
+                            that.confirmLoading = false;
+                        });
+                }
+            });
+        },
+    },
+};
+</script>
+<style scoped>
+.avatar-uploader>.ant-upload {
+    width: 104px;
+    height: 104px;
+}
+</style>

+ 36 - 0
src/views/settings/components/roomModules/roomLayoutDetailForm/roomLayoutDetail.vue

@@ -0,0 +1,36 @@
+<template>
+    <div>
+        <a-form-model ref="form" :model="model" :rules="validatorRules">
+            TODO:详情配置
+        </a-form-model>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'HotelSaasTenantFrontendRoomLayoutDetail',
+
+    data() {
+        return {
+            model: {
+
+            },
+            validatorRules: {
+
+            }
+        };
+    },
+
+    mounted() {
+        
+    },
+
+    methods: {
+        
+    },
+};
+</script>
+
+<style lang="stylus" scoped>
+
+</style>

+ 36 - 0
src/views/settings/components/roomModules/roomLayoutDetailForm/roomLayoutDevice.vue

@@ -0,0 +1,36 @@
+<template>
+    <div>
+        <a-form-model ref="form" :model="model" :rules="validatorRules">
+            TODO:房间配置
+        </a-form-model>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'HotelSaasTenantFrontendRoomLayoutDevice',
+
+    data() {
+        return {
+            model: {
+
+            },
+            validatorRules: {
+
+            }
+        };
+    },
+
+    mounted() {
+        
+    },
+
+    methods: {
+        
+    },
+};
+</script>
+
+<style lang="stylus" scoped>
+
+</style>

+ 36 - 0
src/views/settings/components/roomModules/roomLayoutDetailForm/roomLayoutImage.vue

@@ -0,0 +1,36 @@
+<template>
+    <div>
+        <a-form-model ref="form" :model="model" :rules="validatorRules">
+            TODO:房型大图
+        </a-form-model>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'HotelSaasTenantFrontendRoomLayoutImage',
+
+    data() {
+        return {
+            model: {
+
+            },
+            validatorRules: {
+
+            }
+        };
+    },
+
+    mounted() {
+        
+    },
+
+    methods: {
+        
+    },
+};
+</script>
+
+<style lang="stylus" scoped>
+
+</style>

+ 8 - 1
src/views/settings/components/roomModules/roomLayoutList.vue

@@ -82,7 +82,7 @@
                                 <a @click="handlePriceManager(record)">价格管理</a>
                             </a-menu-item>
                             <a-menu-item>
-                                <a @click="handleInfo(record)">价格管理</a>
+                                <a @click="handleDetailSetting(record)">详细设置</a>
                             </a-menu-item>
                             <a-menu-item>
                                 <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
@@ -96,6 +96,7 @@
         </div>
         <room-layout-form ref="modalForm" @ok="modalFormOk"></room-layout-form>
         <room-layout-price-modal ref="priceModal" @ok="onPriceSave"></room-layout-price-modal>
+        <room-layout-detail-modal ref="detailModal"></room-layout-detail-modal>
     </a-card>
 </template>
   
@@ -103,6 +104,7 @@
 
 import { JeecgListMixin } from "@/mixins/JeecgListMixin";
 import roomLayoutForm from "./RoomLayoutFormModal"; // todo roomLayoutForm 需要替换成房型的表单弹窗
+import RoomLayoutDetailModal from "./RoomLayoutFormDetailModal.vue";
 
 import RoomLayoutPriceModal from "./RoomLayoutPriceModal.vue";
 
@@ -115,6 +117,7 @@ export default {
     components: {
         roomLayoutForm,
         RoomLayoutPriceModal,
+        RoomLayoutDetailModal
     },
     data() {
         return {
@@ -216,6 +219,10 @@ export default {
             this.$refs.priceModal.setRaw(record.id, record.name)
             this.$refs.priceModal.visible = true
         },
+        handleDetailSetting(record) {
+            this.$refs.detailModal.setRaw(record)
+            this.$refs.detailModal.visible = true
+        },
         changeState(e) {
             console.log(e)
         },