store-room-tab.vue 7.36 KB
<template>
	<div class="store-room-tab">
		<el-alert
			type="info"
			:closable="false"
			show-icon
			class="store-room-hint"
			title="维护本门店可预约房间;保存后预约侧可按门店+房间拉取列表。未保存的本地修改在关闭弹窗前会丢失。"
		/>
		<div class="store-room-toolbar" v-if="!readonly">
			<el-button type="primary" size="small" icon="el-icon-plus" @click="addRow">新增一行</el-button>
			<el-button type="success" size="small" icon="el-icon-check" :loading="saving" @click="handleSave">保存房间配置</el-button>
		</div>
		<el-table :data="roomList" border size="small" class="store-room-table" v-loading="loading">
			<el-table-column label="排序" width="88" align="center">
				<template slot-scope="scope">
					<el-input-number
						v-if="!readonly"
						v-model="scope.row.sortNo"
						:min="0"
						:max="9999"
						:controls="false"
						size="small"
						class="store-room-sort"
					/>
					<span v-else>{{ scope.row.sortNo }}</span>
				</template>
			</el-table-column>
			<el-table-column label="房间名称" min-width="140">
				<template slot-scope="scope">
					<el-input v-if="!readonly" v-model="scope.row.roomName" maxlength="64" show-word-limit placeholder="必填" />
					<span v-else>{{ scope.row.roomName || '无' }}</span>
				</template>
			</el-table-column>
			<el-table-column label="类型" width="120">
				<template slot-scope="scope">
					<el-select v-if="!readonly" v-model="scope.row.roomType" placeholder="类型" size="small" style="width:100%">
						<el-option
							v-for="opt in roomTypeOptions"
							:key="normOpt(opt).value"
							:label="normOpt(opt).label"
							:value="normOpt(opt).value"
						/>
					</el-select>
					<span v-else>{{ roomTypeLabel(scope.row.roomType) }}</span>
				</template>
			</el-table-column>
			<el-table-column label="容纳人数" width="110" align="center">
				<template slot-scope="scope">
					<el-input-number
						v-if="!readonly"
						v-model="scope.row.capacity"
						:min="0"
						:max="999"
						:controls="false"
						size="small"
						class="store-room-cap"
						placeholder="可选"
					/>
					<span v-else>{{ scope.row.capacity != null ? scope.row.capacity : '无' }}</span>
				</template>
			</el-table-column>
			<el-table-column label="启用" width="88" align="center">
				<template slot-scope="scope">
					<el-switch v-if="!readonly" :active-value="1" :inactive-value="0" v-model="scope.row.enabled" />
					<el-tag v-else :type="scope.row.enabled === 1 ? 'success' : 'info'" size="small">
						{{ scope.row.enabled === 1 ? '是' : '否' }}
					</el-tag>
				</template>
			</el-table-column>
			<el-table-column label="备注" min-width="120">
				<template slot-scope="scope">
					<el-input v-if="!readonly" v-model="scope.row.remark" maxlength="500" placeholder="可选" />
					<span v-else>{{ scope.row.remark || '无' }}</span>
				</template>
			</el-table-column>
			<el-table-column v-if="!readonly" label="操作" width="72" align="center">
				<template slot-scope="scope">
					<el-button type="text" size="small" class="store-room-del" @click="removeRow(scope.$index)">删除</el-button>
				</template>
			</el-table-column>
		</el-table>
		<p v-if="!roomList.length && !loading" class="store-room-empty">暂无房间,请点击「新增一行」后保存。</p>
	</div>
</template>

<script>
import { getStoreRoomTypeSelector, getStoreRoomsByStoreId, saveStoreRooms } from '@/api/extend/lqMdRoom'

export default {
	name: 'StoreRoomTab',
	props: {
		storeId: {
			type: String,
			default: ''
		},
		readonly: {
			type: Boolean,
			default: false
		}
	},
	data() {
		return {
			loading: false,
			saving: false,
			roomList: [],
			roomTypeOptions: []
		}
	},
	created() {
		this.loadRoomTypeOptions()
	},
	watch: {
		storeId: {
			immediate: true,
			handler(val) {
				if (val === null || val === undefined || val === '') {
					this.roomList = []
					return
				}
				this.$nextTick(() => {
					this.loadRooms()
				})
			}
		}
	},
	methods: {
		normOpt(item) {
			const v = item.value != null ? item.value : item.Value
			const label = item.description || item.Description || item.name || item.Name || String(v)
			return { value: v, label }
		},
		roomTypeLabel(val) {
			const o = this.roomTypeOptions.map(x => this.normOpt(x)).find(x => x.value === val)
			return o ? o.label : '无'
		},
		loadRoomTypeOptions() {
			getStoreRoomTypeSelector()
				.then(res => {
					this.roomTypeOptions = res.data || []
				})
				.catch(() => {
					this.roomTypeOptions = []
				})
		},
		normalizeRoomRow(r) {
			if (!r) return null
			return {
				id: r.id != null ? r.id : r.Id,
				storeId: r.storeId != null ? r.storeId : r.StoreId,
				roomName: r.roomName != null ? r.roomName : r.RoomName,
				sortNo: r.sortNo != null ? r.sortNo : (r.SortNo != null ? r.SortNo : 0),
				enabled: r.enabled != null ? r.enabled : (r.Enabled != null ? r.Enabled : 1),
				roomType: r.roomType != null ? r.roomType : (r.RoomType != null ? r.RoomType : 9),
				capacity: r.capacity != null ? r.capacity : r.Capacity,
				remark: r.remark != null ? r.remark : r.Remark
			}
		},
		loadRooms() {
			const sid = this.storeId != null && this.storeId !== '' ? String(this.storeId) : ''
			if (!sid) return
			this.loading = true
			getStoreRoomsByStoreId(sid)
				.then(res => {
					const d = res && res.data !== undefined ? res.data : res
					const raw =
						(d && d.list) ||
						(d && d.List) ||
						(Array.isArray(d) ? d : []) ||
						[]
					this.roomList = (Array.isArray(raw) ? raw : []).map(x => this.normalizeRoomRow(x)).filter(Boolean)
				})
				.catch(() => {
					this.roomList = []
				})
				.finally(() => {
					this.loading = false
				})
		},
		addRow() {
			if (this.readonly) return
			this.roomList.push({
				id: '',
				roomName: '',
				sortNo: this.roomList.length,
				enabled: 1,
				roomType: 9,
				capacity: undefined,
				remark: ''
			})
		},
		removeRow(index) {
			if (this.readonly) return
			this.roomList.splice(index, 1)
		},
		handleSave() {
			if (!this.storeId) {
				this.$message.warning('请先保存门店后再维护房间')
				return
			}
			if (this.readonly) return
			for (let i = 0; i < this.roomList.length; i++) {
				const row = this.roomList[i]
				if (!row.roomName || !String(row.roomName).trim()) {
					this.$message.warning(`第 ${i + 1} 行:房间名称不能为空`)
					return
				}
			}
			const rooms = this.roomList.map(r => ({
				id: r.id || undefined,
				roomName: String(r.roomName).trim(),
				sortNo: r.sortNo != null ? r.sortNo : 0,
				enabled: r.enabled === 0 ? 0 : 1,
				roomType: r.roomType != null ? r.roomType : 9,
				capacity: r.capacity === '' || r.capacity === undefined || r.capacity === null ? null : r.capacity,
				remark: r.remark ? String(r.remark).trim() : null
			}))
			this.saving = true
			saveStoreRooms({ storeId: this.storeId, rooms })
				.then(() => {
					this.$message.success('房间配置已保存')
					this.loadRooms()
				})
				.catch(() => {})
				.finally(() => {
					this.saving = false
				})
		}
	}
}
</script>

<style scoped lang="scss">
.store-room-tab {
	padding-top: 4px;
}
.store-room-hint {
	margin-bottom: 12px;
}
.store-room-toolbar {
	display: flex;
	align-items: center;
	gap: 10px;
	margin-bottom: 12px;
}
.store-room-table {
	width: 100%;
}
.store-room-sort,
.store-room-cap {
	width: 100%;
}
.store-room-del {
	color: #f56c6c;
}
.store-room-empty {
	margin: 12px 0 0;
	color: #909399;
	font-size: 13px;
}
</style>