|
|
@@ -1,56 +1,21 @@
|
|
|
<template>
|
|
|
<div class="allocate-popup-container">
|
|
|
- <van-popup
|
|
|
- class="allocate-popup"
|
|
|
- v-model:show="state.dialog.isShowDialog"
|
|
|
- position="right"
|
|
|
- :style="{ width: '100%' }"
|
|
|
- closeable
|
|
|
- :close-on-popstate="false"
|
|
|
- @close="onCancel"
|
|
|
- >
|
|
|
+ <van-popup class="allocate-popup" v-model:show="state.dialog.isShowDialog" position="right"
|
|
|
+ :style="{ width: '100%' }" closeable :close-on-popstate="false" @close="onCancel">
|
|
|
<header class="popup-header">
|
|
|
<div class="popup-title">资源分配</div>
|
|
|
<div class="popup-controls">
|
|
|
- <div
|
|
|
- class="group-selector"
|
|
|
- @click="groupPickerVisible = true"
|
|
|
- >
|
|
|
+ <div class="group-selector" @click="groupPickerVisible = true">
|
|
|
<span class="label">资源组</span>
|
|
|
- <van-field
|
|
|
- :model-value="groupLabel"
|
|
|
- readonly
|
|
|
- is-link
|
|
|
- input-align="right"
|
|
|
- placeholder="全部资源组"
|
|
|
- border
|
|
|
- />
|
|
|
+ <van-field :model-value="groupLabel" readonly is-link input-align="right" placeholder="全部资源组" border />
|
|
|
</div>
|
|
|
- <van-popup
|
|
|
- v-model:show="groupPickerVisible"
|
|
|
- round
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker
|
|
|
- title="选择资源组"
|
|
|
- show-toolbar
|
|
|
- :columns="groupOptions"
|
|
|
- @cancel="groupPickerVisible = false"
|
|
|
- @confirm="onGroupConfirm"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="groupPickerVisible" round position="bottom">
|
|
|
+ <van-picker title="选择资源组" show-toolbar :columns="groupOptions" @cancel="groupPickerVisible = false"
|
|
|
+ @confirm="onGroupConfirm" />
|
|
|
</van-popup>
|
|
|
- <van-radio-group
|
|
|
- v-model="resClass"
|
|
|
- direction="horizontal"
|
|
|
- class="type-radio-group"
|
|
|
- @change="filterOutList"
|
|
|
- >
|
|
|
+ <van-radio-group v-model="resClass" direction="horizontal" class="type-radio-group" @change="filterOutList">
|
|
|
<van-radio name="">全部</van-radio>
|
|
|
- <van-radio
|
|
|
- v-for="item in cellType"
|
|
|
- :key="item.dictValue"
|
|
|
- :name="item.dictValue"
|
|
|
- >
|
|
|
+ <van-radio v-for="item in cellType" :key="item.dictValue" :name="item.dictValue">
|
|
|
{{ item.dictLabel }}
|
|
|
</van-radio>
|
|
|
</van-radio-group>
|
|
|
@@ -59,18 +24,10 @@
|
|
|
<div class="popup-body">
|
|
|
<section class="card confirm-card">
|
|
|
<div class="info-banner warning">待分配队列(已确认{{ comfirmTotal }}人)</div>
|
|
|
- <van-empty
|
|
|
- v-if="!state.confirmList.length"
|
|
|
- image="default"
|
|
|
- description="暂无队列数据"
|
|
|
- />
|
|
|
+ <van-empty v-if="!state.confirmList.length" image="default" description="暂无队列数据" />
|
|
|
<ul v-else>
|
|
|
- <li
|
|
|
- v-for="(item, index) in state.confirmList"
|
|
|
- :key="index"
|
|
|
- :class="{ active: index === state.active }"
|
|
|
- @click="state.active = index"
|
|
|
- >
|
|
|
+ <li v-for="(item, index) in state.confirmList" :key="index" :class="{ active: index === state.active }"
|
|
|
+ @click="state.active = index">
|
|
|
<div class="text">
|
|
|
<p>
|
|
|
分配房间:
|
|
|
@@ -89,19 +46,10 @@
|
|
|
</p>
|
|
|
</div>
|
|
|
<div class="btns">
|
|
|
- <button
|
|
|
- v-if="item.resId"
|
|
|
- class="link-btn danger"
|
|
|
- type="button"
|
|
|
- @click.stop="cancelAllocate(item)"
|
|
|
- >
|
|
|
+ <button v-if="item.resId" class="link-btn danger" type="button" @click.stop="cancelAllocate(item)">
|
|
|
取消
|
|
|
</button>
|
|
|
- <button
|
|
|
- class="link-btn"
|
|
|
- type="button"
|
|
|
- @click.stop="onDetail(item)"
|
|
|
- >
|
|
|
+ <button class="link-btn" type="button" @click.stop="onDetail(item)">
|
|
|
查看
|
|
|
</button>
|
|
|
</div>
|
|
|
@@ -110,28 +58,13 @@
|
|
|
</section>
|
|
|
<section class="card resource-card">
|
|
|
<div class="info-banner warning">资源列表(共{{ state.resourceList.length }}个)</div>
|
|
|
- <van-empty
|
|
|
- v-if="!state.resourceList.length"
|
|
|
- image="search"
|
|
|
- description="暂无资源数据"
|
|
|
- />
|
|
|
- <div
|
|
|
- v-else
|
|
|
- class="resource-grid"
|
|
|
- >
|
|
|
- <div
|
|
|
- v-for="item in state.resourceList"
|
|
|
- :key="item.id"
|
|
|
- class="resource-item"
|
|
|
- :class="{ active: curSelectedResourceId === item.id }"
|
|
|
- @click="onSelectResource(item)"
|
|
|
- >
|
|
|
+ <van-empty v-if="!state.resourceList.length" image="search" description="暂无资源数据" />
|
|
|
+ <div v-else class="resource-grid">
|
|
|
+ <div v-for="item in state.resourceList" :key="item.id" class="resource-item"
|
|
|
+ :class="{ active: curSelectedResourceId === item.id }" @click="onSelectResource(item)">
|
|
|
<div class="resource-header">
|
|
|
<span class="resource-name">{{ item.resName }}</span>
|
|
|
- <van-tag
|
|
|
- type="primary"
|
|
|
- plain
|
|
|
- >
|
|
|
+ <van-tag type="primary" plain>
|
|
|
{{ getDictLabel(cellType, item.resClass) }}
|
|
|
</van-tag>
|
|
|
</div>
|
|
|
@@ -139,11 +72,7 @@
|
|
|
<div class="resource-footer">
|
|
|
<span class="resource-usage">{{ item.usingSource || 0 }}/{{ item.maxNum }}</span>
|
|
|
<ul class="usage-dots">
|
|
|
- <li
|
|
|
- v-for="(p, index) in item.usedList"
|
|
|
- :key="index"
|
|
|
- :class="getUsedClass(p)"
|
|
|
- ></li>
|
|
|
+ <li v-for="(p, index) in item.usedList" :key="index" :class="getUsedClass(p)"></li>
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -153,33 +82,19 @@
|
|
|
<div class="info-banner warning">房间使用情况</div>
|
|
|
<div class="usage-list">
|
|
|
<ul class="position-choose">
|
|
|
- <li
|
|
|
- v-for="(p, index) in allocationSituationList"
|
|
|
- :key="index"
|
|
|
- >
|
|
|
+ <li v-for="(p, index) in allocationSituationList" :key="index">
|
|
|
<i :class="getUsedClass(p)"></i>
|
|
|
<div class="txt-flex">
|
|
|
- <span
|
|
|
- v-if="p.userObj"
|
|
|
- :title="p.userObj.memberName"
|
|
|
- >
|
|
|
+ <span v-if="p.userObj" :title="p.userObj.memberName">
|
|
|
{{ p.userObj.memberName }}
|
|
|
</span>
|
|
|
- <span
|
|
|
- v-else-if="p.userName"
|
|
|
- :title="p.userName"
|
|
|
- >
|
|
|
+ <span v-else-if="p.userName" :title="p.userName">
|
|
|
{{ p.userName }}
|
|
|
</span>
|
|
|
<span v-else>空闲</span>
|
|
|
</div>
|
|
|
- <van-button
|
|
|
- v-if="!p.userObj && (p.assignStatus == '10' || p.assignStatus == '40')"
|
|
|
- type="primary"
|
|
|
- size="mini"
|
|
|
- plain
|
|
|
- @click.stop="onAllocate(p)"
|
|
|
- >
|
|
|
+ <van-button v-if="!p.userObj && (p.assignStatus == '10' || p.assignStatus == '40')" type="primary"
|
|
|
+ size="mini" plain @click.stop="onAllocate(p)">
|
|
|
分配
|
|
|
</van-button>
|
|
|
</li>
|
|
|
@@ -188,19 +103,10 @@
|
|
|
</section>
|
|
|
</div>
|
|
|
<div class="popup-footer">
|
|
|
- <van-button
|
|
|
- type="primary"
|
|
|
- plain
|
|
|
- block
|
|
|
- @click="onCancel"
|
|
|
- >
|
|
|
+ <van-button type="primary" plain block @click="onCancel">
|
|
|
取 消
|
|
|
</van-button>
|
|
|
- <van-button
|
|
|
- type="primary"
|
|
|
- block
|
|
|
- @click="onSubmit('20')"
|
|
|
- >
|
|
|
+ <van-button type="primary" block @click="onSubmit('20')">
|
|
|
确 定
|
|
|
</van-button>
|
|
|
</div>
|
|
|
@@ -210,722 +116,788 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts" name="entryAllocate">
|
|
|
- import to from 'await-to-js'
|
|
|
- import { reactive, ref, defineAsyncComponent, computed } from 'vue'
|
|
|
- import { showToast, showConfirmDialog } from 'vant'
|
|
|
- import { getDictLabel } from '/@/utils/other'
|
|
|
- import { usePlatformApi } from '/@/api/platform/home'
|
|
|
- import { useSystemApi } from '/@/api/platform/system'
|
|
|
- import { useUserInfo } from '/@/stores/userInfo'
|
|
|
- import { storeToRefs } from 'pinia'
|
|
|
- import { useDictApi } from '/@/api/base/system/dict'
|
|
|
- import { useCellAssignApi } from '/@/api/platform/home/assign'
|
|
|
- import { formatDate } from '/@/utils/formatTime'
|
|
|
-
|
|
|
- const DetailsDialog = defineAsyncComponent(() => import('/@/view/entry/components/details.vue'))
|
|
|
- const stores = useUserInfo()
|
|
|
- const { userInfos } = storeToRefs(stores)
|
|
|
-
|
|
|
- // 定义子组件向父组件传值/事件
|
|
|
- const emit = defineEmits(['refresh'])
|
|
|
-
|
|
|
- // 定义变量内容
|
|
|
- const systemApi = useSystemApi()
|
|
|
- const platformApi = usePlatformApi()
|
|
|
- const dictApi = useDictApi()
|
|
|
- const userTypeList = ref<RowDicDataType[]>([])
|
|
|
- const projectGroupList = ref<any[]>([])
|
|
|
- const cellType = ref<RowDicDataType[]>([])
|
|
|
- const originalResourceList = ref<any[]>([])
|
|
|
- const resourceList = ref<any[]>([])
|
|
|
- const molecularGroupList = ref<any[]>([])
|
|
|
- const cellAssignApi = useCellAssignApi()
|
|
|
-
|
|
|
- const state = reactive({
|
|
|
- form: {
|
|
|
- id: 0,
|
|
|
- memberId: 0,
|
|
|
- memberName: '',
|
|
|
- memberPhone: '',
|
|
|
- memberSex: '',
|
|
|
- memberNo: '',
|
|
|
- memberIden: '',
|
|
|
- startDate: '',
|
|
|
- endDate: '',
|
|
|
- memberType: '',
|
|
|
- deptId: 0,
|
|
|
- deptName: '',
|
|
|
- workPlace: '',
|
|
|
- mentorId: 0,
|
|
|
- mentorName: '',
|
|
|
- mentorPhone: '',
|
|
|
- mentorDeptId: 0,
|
|
|
- mentorDeptName: '',
|
|
|
- platformId: 0,
|
|
|
- platformName: '',
|
|
|
- platformType: '',
|
|
|
- platformTime: 0,
|
|
|
- other: '',
|
|
|
- isTemporary: '',
|
|
|
- },
|
|
|
- confirmList: [] as any[],
|
|
|
- resourceList: [] as any[],
|
|
|
- active: -1,
|
|
|
- dialog: {
|
|
|
- isShowDialog: false,
|
|
|
- type: '',
|
|
|
- title: '',
|
|
|
- submitTxt: '',
|
|
|
- },
|
|
|
- })
|
|
|
- const comfirmTotal = computed(() => {
|
|
|
- return state.confirmList.reduce((pre: number, cur: any) => {
|
|
|
- if (cur.resId) return pre + 1
|
|
|
- return pre
|
|
|
- }, 0)
|
|
|
- })
|
|
|
- const originalConfirmList = ref<any[]>([])
|
|
|
- const confirmList = ref<any[]>([])
|
|
|
- const belongOrgOption = ref<any[]>([])
|
|
|
- const userList = ref<any[]>([])
|
|
|
- const platformList = ref()
|
|
|
- const resClass = ref('')
|
|
|
- const groupId = ref('') // 资源组ID
|
|
|
- const groupPickerVisible = ref(false)
|
|
|
- const detailsDialog = ref()
|
|
|
- const curSelectedResourceId = ref(0) // 当前选中的资源ID
|
|
|
- const allocationSituationList = ref<any[]>([]) // 资源分配情况列表
|
|
|
- const groupOptions = computed(() => {
|
|
|
- const options = molecularGroupList.value.map((item: any) => ({
|
|
|
- text: item.groupName,
|
|
|
- value: String(item.id),
|
|
|
- }))
|
|
|
- return [{ text: '全部资源组', value: '' }, ...options]
|
|
|
- })
|
|
|
- const groupLabel = computed(() => {
|
|
|
- const option = groupOptions.value.find((item) => item.value === groupId.value)
|
|
|
- return option ? option.text : '全部资源组'
|
|
|
- })
|
|
|
- const onGroupConfirm = (value: any, detail?: any) => {
|
|
|
- let option: any = null
|
|
|
- if (value && typeof value === 'object' && 'selectedOptions' in value) {
|
|
|
- option = value.selectedOptions?.[0]
|
|
|
- } else if (detail && typeof detail === 'object' && 'selectedOptions' in detail) {
|
|
|
- option = detail.selectedOptions?.[0]
|
|
|
- } else if (Array.isArray(value)) {
|
|
|
- const target = value[0]
|
|
|
- option = groupOptions.value.find((item) => item.value === target)
|
|
|
- } else if (value && typeof value === 'object') {
|
|
|
- option = value
|
|
|
- }
|
|
|
- groupId.value = option?.value ?? ''
|
|
|
- groupPickerVisible.value = false
|
|
|
- filterOutListByGroupId(groupId.value)
|
|
|
- }
|
|
|
- const getDicts = () => {
|
|
|
- Promise.all([
|
|
|
- systemApi.getDeptTree(),
|
|
|
- systemApi.getUserList({ noPage: true }),
|
|
|
- platformApi.getAllPlatformList({ noPage: true }),
|
|
|
- dictApi.getDictDataByType('sys_user_type'),
|
|
|
- systemApi.getProjectGroupListForApp({ noPage: true }),
|
|
|
- userInfos.value.platformId != 0 ? platformApi.getResourceTypeDict({ id: userInfos.value.platformId }) : '',
|
|
|
- ]).then(([dept, user, plat, type, pjt, cell]) => {
|
|
|
- belongOrgOption.value = dept?.data || []
|
|
|
- userList.value = user?.data?.list || []
|
|
|
- platformList.value = plat?.data?.list || []
|
|
|
- userTypeList.value = type?.data?.values || []
|
|
|
- projectGroupList.value = pjt?.data?.list || []
|
|
|
- cellType.value = cell?.data || []
|
|
|
- })
|
|
|
- }
|
|
|
- const getMolecularGroupList = async () => {
|
|
|
- const [err, res]: ToResponse = await to(platformApi.getMolecularGroupList({ id: userInfos.value.platformId }))
|
|
|
- if (err) return
|
|
|
- molecularGroupList.value = res?.data || []
|
|
|
- }
|
|
|
- const getResourceList = async () => {
|
|
|
- const [err, res]: ToResponse = await to(
|
|
|
- platformApi.getResourceList({ platformId: userInfos.value.platformId, resStatus: '10' }),
|
|
|
- )
|
|
|
- if (err) return
|
|
|
- originalResourceList.value = JSON.parse(JSON.stringify(res?.data?.list || []))
|
|
|
- resourceList.value = JSON.parse(JSON.stringify(originalResourceList.value))
|
|
|
- state.resourceList = JSON.parse(JSON.stringify(resourceList.value))
|
|
|
- }
|
|
|
- // 待分配列表
|
|
|
- const getConfirmList = async () => {
|
|
|
- const [err, res]: ToResponse = await to(cellAssignApi.assignQueue({ platformId: userInfos.value.platformId }))
|
|
|
- if (err) return
|
|
|
- originalConfirmList.value = JSON.parse(JSON.stringify(res?.data || []))
|
|
|
- confirmList.value = JSON.parse(JSON.stringify(originalConfirmList.value))
|
|
|
- state.confirmList = JSON.parse(JSON.stringify(confirmList.value))
|
|
|
- }
|
|
|
- // 打开弹窗
|
|
|
- const openDialog = async (type: string, row: number) => {
|
|
|
- getDicts()
|
|
|
- getResourceList()
|
|
|
- getConfirmList()
|
|
|
- getMolecularGroupList()
|
|
|
- state.dialog.type = type
|
|
|
- state.dialog.title = '入室资源分配'
|
|
|
- state.dialog.isShowDialog = true
|
|
|
- }
|
|
|
- // 前端筛选类型
|
|
|
- const filterOutList = (val: string) => {
|
|
|
- if (val) {
|
|
|
- state.resourceList = resourceList.value.filter((item: any) => item.resClass == val)
|
|
|
- state.confirmList = confirmList.value.filter((item: any) => item.cellSourceType == val)
|
|
|
- } else {
|
|
|
- state.resourceList = [...resourceList.value]
|
|
|
- state.confirmList = [...confirmList.value]
|
|
|
- }
|
|
|
- }
|
|
|
- // 前端筛选资源组
|
|
|
- const filterOutListByGroupId = (val: string) => {
|
|
|
- if (val) {
|
|
|
- state.resourceList = resourceList.value.filter((item: any) => String(item.groupId) === val)
|
|
|
- } else {
|
|
|
- state.resourceList = [...resourceList.value]
|
|
|
- }
|
|
|
- }
|
|
|
- // 选择资源房间
|
|
|
- const onSelectResource = (row: any) => {
|
|
|
- curSelectedResourceId.value = row.id
|
|
|
- allocationSituationList.value = row.usedList
|
|
|
- }
|
|
|
- // 确认
|
|
|
- const onConfirm = (row: any) => {
|
|
|
- // 验证同类型 下个月出室人员 = 已确认人数 提示无法确认
|
|
|
- }
|
|
|
- // 关闭弹窗
|
|
|
- const resetDialogState = () => {
|
|
|
- confirmList.value = JSON.parse(JSON.stringify(originalConfirmList.value))
|
|
|
- state.confirmList = JSON.parse(JSON.stringify(confirmList.value))
|
|
|
- resourceList.value = JSON.parse(JSON.stringify(originalResourceList.value))
|
|
|
- state.resourceList = JSON.parse(JSON.stringify(resourceList.value))
|
|
|
- allocationSituationList.value = []
|
|
|
- curSelectedResourceId.value = 0
|
|
|
- resClass.value = ''
|
|
|
- groupId.value = ''
|
|
|
- state.active = -1
|
|
|
+import to from 'await-to-js'
|
|
|
+import { reactive, ref, defineAsyncComponent, computed } from 'vue'
|
|
|
+import { showToast, showConfirmDialog } from 'vant'
|
|
|
+import { getDictLabel } from '/@/utils/other'
|
|
|
+import { usePlatformApi } from '/@/api/platform/home'
|
|
|
+import { useSystemApi } from '/@/api/platform/system'
|
|
|
+import { useUserInfo } from '/@/stores/userInfo'
|
|
|
+import { storeToRefs } from 'pinia'
|
|
|
+import { useDictApi } from '/@/api/base/system/dict'
|
|
|
+import { useCellAssignApi } from '/@/api/platform/home/assign'
|
|
|
+import { formatDate } from '/@/utils/formatTime'
|
|
|
+
|
|
|
+const DetailsDialog = defineAsyncComponent(() => import('/@/view/entry/components/details.vue'))
|
|
|
+const stores = useUserInfo()
|
|
|
+const { userInfos } = storeToRefs(stores)
|
|
|
+
|
|
|
+// 定义子组件向父组件传值/事件
|
|
|
+const emit = defineEmits(['refresh'])
|
|
|
+
|
|
|
+// 定义变量内容
|
|
|
+const systemApi = useSystemApi()
|
|
|
+const platformApi = usePlatformApi()
|
|
|
+const dictApi = useDictApi()
|
|
|
+const userTypeList = ref<RowDicDataType[]>([])
|
|
|
+const projectGroupList = ref<any[]>([])
|
|
|
+const cellType = ref<RowDicDataType[]>([])
|
|
|
+const originalResourceList = ref<any[]>([])
|
|
|
+const resourceList = ref<any[]>([])
|
|
|
+const molecularGroupList = ref<any[]>([])
|
|
|
+const cellAssignApi = useCellAssignApi()
|
|
|
+
|
|
|
+const state = reactive({
|
|
|
+ form: {
|
|
|
+ id: 0,
|
|
|
+ memberId: 0,
|
|
|
+ memberName: '',
|
|
|
+ memberPhone: '',
|
|
|
+ memberSex: '',
|
|
|
+ memberNo: '',
|
|
|
+ memberIden: '',
|
|
|
+ startDate: '',
|
|
|
+ endDate: '',
|
|
|
+ memberType: '',
|
|
|
+ deptId: 0,
|
|
|
+ deptName: '',
|
|
|
+ workPlace: '',
|
|
|
+ mentorId: 0,
|
|
|
+ mentorName: '',
|
|
|
+ mentorPhone: '',
|
|
|
+ mentorDeptId: 0,
|
|
|
+ mentorDeptName: '',
|
|
|
+ platformId: 0,
|
|
|
+ platformName: '',
|
|
|
+ platformType: '',
|
|
|
+ platformTime: 0,
|
|
|
+ other: '',
|
|
|
+ isTemporary: '',
|
|
|
+ },
|
|
|
+ confirmList: [] as any[],
|
|
|
+ resourceList: [] as any[],
|
|
|
+ active: -1,
|
|
|
+ dialog: {
|
|
|
+ isShowDialog: false,
|
|
|
+ type: '',
|
|
|
+ title: '',
|
|
|
+ submitTxt: '',
|
|
|
+ },
|
|
|
+})
|
|
|
+const comfirmTotal = computed(() => {
|
|
|
+ return state.confirmList.reduce((pre: number, cur: any) => {
|
|
|
+ if (cur.resId) return pre + 1
|
|
|
+ return pre
|
|
|
+ }, 0)
|
|
|
+})
|
|
|
+const originalConfirmList = ref<any[]>([])
|
|
|
+const confirmList = ref<any[]>([])
|
|
|
+const belongOrgOption = ref<any[]>([])
|
|
|
+const userList = ref<any[]>([])
|
|
|
+const platformList = ref()
|
|
|
+const resClass = ref('')
|
|
|
+const groupId = ref('') // 资源组ID
|
|
|
+const groupPickerVisible = ref(false)
|
|
|
+const detailsDialog = ref()
|
|
|
+const curSelectedResourceId = ref(0) // 当前选中的资源ID
|
|
|
+const allocationSituationList = ref<any[]>([]) // 资源分配情况列表
|
|
|
+const groupOptions = computed(() => {
|
|
|
+ const options = molecularGroupList.value.map((item: any) => ({
|
|
|
+ text: item.groupName,
|
|
|
+ value: String(item.id),
|
|
|
+ }))
|
|
|
+ return [{ text: '全部资源组', value: '' }, ...options]
|
|
|
+})
|
|
|
+const groupLabel = computed(() => {
|
|
|
+ const option = groupOptions.value.find((item) => item.value === groupId.value)
|
|
|
+ return option ? option.text : '全部资源组'
|
|
|
+})
|
|
|
+const onGroupConfirm = (value: any, detail?: any) => {
|
|
|
+ let option: any = null
|
|
|
+ if (value && typeof value === 'object' && 'selectedOptions' in value) {
|
|
|
+ option = value.selectedOptions?.[0]
|
|
|
+ } else if (detail && typeof detail === 'object' && 'selectedOptions' in detail) {
|
|
|
+ option = detail.selectedOptions?.[0]
|
|
|
+ } else if (Array.isArray(value)) {
|
|
|
+ const target = value[0]
|
|
|
+ option = groupOptions.value.find((item) => item.value === target)
|
|
|
+ } else if (value && typeof value === 'object') {
|
|
|
+ option = value
|
|
|
}
|
|
|
- const closeDialog = () => {
|
|
|
- resetDialogState()
|
|
|
- state.dialog.isShowDialog = false
|
|
|
- emit('refresh')
|
|
|
+ groupId.value = option?.value ?? ''
|
|
|
+ groupPickerVisible.value = false
|
|
|
+ filterOutListByGroupId(groupId.value)
|
|
|
+}
|
|
|
+const getDicts = () => {
|
|
|
+ Promise.all([
|
|
|
+ systemApi.getDeptTree(),
|
|
|
+ systemApi.getUserList({ noPage: true }),
|
|
|
+ platformApi.getAllPlatformList({ noPage: true }),
|
|
|
+ dictApi.getDictDataByType('sys_user_type'),
|
|
|
+ systemApi.getProjectGroupListForApp({ noPage: true }),
|
|
|
+ userInfos.value.platformId != 0 ? platformApi.getResourceTypeDict({ id: userInfos.value.platformId }) : '',
|
|
|
+ ]).then(([dept, user, plat, type, pjt, cell]) => {
|
|
|
+ belongOrgOption.value = dept?.data || []
|
|
|
+ userList.value = user?.data?.list || []
|
|
|
+ platformList.value = plat?.data?.list || []
|
|
|
+ userTypeList.value = type?.data?.values || []
|
|
|
+ projectGroupList.value = pjt?.data?.list || []
|
|
|
+ cellType.value = cell?.data || []
|
|
|
+ })
|
|
|
+}
|
|
|
+const getMolecularGroupList = async () => {
|
|
|
+ const [err, res]: ToResponse = await to(platformApi.getMolecularGroupList({ id: userInfos.value.platformId }))
|
|
|
+ if (err) return
|
|
|
+ molecularGroupList.value = res?.data || []
|
|
|
+}
|
|
|
+const getResourceList = async () => {
|
|
|
+ const [err, res]: ToResponse = await to(
|
|
|
+ platformApi.getResourceList({ platformId: userInfos.value.platformId, resStatus: '10' }),
|
|
|
+ )
|
|
|
+ if (err) return
|
|
|
+ originalResourceList.value = JSON.parse(JSON.stringify(res?.data?.list || []))
|
|
|
+ resourceList.value = JSON.parse(JSON.stringify(originalResourceList.value))
|
|
|
+ state.resourceList = JSON.parse(JSON.stringify(resourceList.value))
|
|
|
+}
|
|
|
+// 待分配列表
|
|
|
+const getConfirmList = async () => {
|
|
|
+ const [err, res]: ToResponse = await to(cellAssignApi.assignQueue({ platformId: userInfos.value.platformId }))
|
|
|
+ if (err) return
|
|
|
+ originalConfirmList.value = JSON.parse(JSON.stringify(res?.data || []))
|
|
|
+ confirmList.value = JSON.parse(JSON.stringify(originalConfirmList.value))
|
|
|
+ state.confirmList = JSON.parse(JSON.stringify(confirmList.value))
|
|
|
+}
|
|
|
+// 打开弹窗
|
|
|
+const openDialog = async (type: string, row: number) => {
|
|
|
+ getDicts()
|
|
|
+ getResourceList()
|
|
|
+ getConfirmList()
|
|
|
+ getMolecularGroupList()
|
|
|
+ state.dialog.type = type
|
|
|
+ state.dialog.title = '入室资源分配'
|
|
|
+ state.dialog.isShowDialog = true
|
|
|
+}
|
|
|
+// 前端筛选类型
|
|
|
+const filterOutList = (val: string) => {
|
|
|
+ if (val) {
|
|
|
+ state.resourceList = resourceList.value.filter((item: any) => item.resClass == val)
|
|
|
+ state.confirmList = confirmList.value.filter((item: any) => item.cellSourceType == val)
|
|
|
+ } else {
|
|
|
+ state.resourceList = [...resourceList.value]
|
|
|
+ state.confirmList = [...confirmList.value]
|
|
|
}
|
|
|
- // 取消
|
|
|
- const onCancel = () => {
|
|
|
- closeDialog()
|
|
|
+}
|
|
|
+// 前端筛选资源组
|
|
|
+const filterOutListByGroupId = (val: string) => {
|
|
|
+ if (val) {
|
|
|
+ state.resourceList = resourceList.value.filter((item: any) => String(item.groupId) === val)
|
|
|
+ } else {
|
|
|
+ state.resourceList = [...resourceList.value]
|
|
|
}
|
|
|
+}
|
|
|
+// 选择资源房间
|
|
|
+const onSelectResource = (row: any) => {
|
|
|
+ curSelectedResourceId.value = row.id
|
|
|
+ allocationSituationList.value = row.usedList
|
|
|
+}
|
|
|
+// 确认
|
|
|
+const onConfirm = (row: any) => {
|
|
|
+ // 验证同类型 下个月出室人员 = 已确认人数 提示无法确认
|
|
|
+}
|
|
|
+// 关闭弹窗
|
|
|
+const resetDialogState = () => {
|
|
|
+ confirmList.value = JSON.parse(JSON.stringify(originalConfirmList.value))
|
|
|
+ state.confirmList = JSON.parse(JSON.stringify(confirmList.value))
|
|
|
+ resourceList.value = JSON.parse(JSON.stringify(originalResourceList.value))
|
|
|
+ state.resourceList = JSON.parse(JSON.stringify(resourceList.value))
|
|
|
+ allocationSituationList.value = []
|
|
|
+ curSelectedResourceId.value = 0
|
|
|
+ resClass.value = ''
|
|
|
+ groupId.value = ''
|
|
|
+ state.active = -1
|
|
|
+}
|
|
|
+const closeDialog = () => {
|
|
|
+ resetDialogState()
|
|
|
+ state.dialog.isShowDialog = false
|
|
|
+}
|
|
|
+// 取消
|
|
|
+const onCancel = () => {
|
|
|
+ closeDialog()
|
|
|
+}
|
|
|
|
|
|
- const handelBatchAssign = async () => {
|
|
|
- const checkedUser = state.confirmList.filter((item: any) => item.checked)
|
|
|
- console.log(checkedUser)
|
|
|
- if (!checkedUser.length) {
|
|
|
- showToast({ message: '请选择待分配队列人员', type: 'text' })
|
|
|
- return
|
|
|
- }
|
|
|
- showConfirmDialog({
|
|
|
- title: '提示',
|
|
|
- message: '是否将选中队列人员一键分配资源?',
|
|
|
- confirmButtonText: '确认',
|
|
|
- cancelButtonText: '取消',
|
|
|
+const handelBatchAssign = async () => {
|
|
|
+ const checkedUser = state.confirmList.filter((item: any) => item.checked)
|
|
|
+ console.log(checkedUser)
|
|
|
+ if (!checkedUser.length) {
|
|
|
+ showToast({ message: '请选择待分配队列人员', type: 'text' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '提示',
|
|
|
+ message: '是否将选中队列人员一键分配资源?',
|
|
|
+ confirmButtonText: '确认',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ const [err]: ToResponse = await to(
|
|
|
+ platformApi.batchAssign({ appointIds: checkedUser.map((item: any) => item.id) }),
|
|
|
+ )
|
|
|
+ if (err) return
|
|
|
+ showToast({ message: '一键分配成功', type: 'success' })
|
|
|
+ getResourceList()
|
|
|
+ getConfirmList()
|
|
|
})
|
|
|
- .then(async () => {
|
|
|
- const [err]: ToResponse = await to(
|
|
|
- platformApi.batchAssign({ appointIds: checkedUser.map((item: any) => item.id) }),
|
|
|
- )
|
|
|
- if (err) return
|
|
|
- showToast({ message: '一键分配成功', type: 'success' })
|
|
|
- getResourceList()
|
|
|
- getConfirmList()
|
|
|
- })
|
|
|
- .catch(() => {})
|
|
|
+ .catch(() => { })
|
|
|
+}
|
|
|
+// 提交
|
|
|
+const onSubmit = async (type: string) => {
|
|
|
+ const arr = confirmList.value.filter((item: any) => item.resId)
|
|
|
+ if (!arr.length) {
|
|
|
+ showToast({ message: '请分配资源', type: 'text' })
|
|
|
+ return
|
|
|
}
|
|
|
- // 提交
|
|
|
- const onSubmit = async (type: string) => {
|
|
|
- const arr = confirmList.value.filter((item: any) => item.resId)
|
|
|
- if (!arr.length) {
|
|
|
- showToast({ message: '请分配资源', type: 'text' })
|
|
|
- return
|
|
|
- }
|
|
|
|
|
|
- const [err]: ToResponse = await to(
|
|
|
- cellAssignApi.create({
|
|
|
- assignList: arr.map((item: any) => {
|
|
|
- return {
|
|
|
- appointId: item.id,
|
|
|
- resId: item.resId,
|
|
|
- location: item.location,
|
|
|
- replaceId: item.replaceId,
|
|
|
- mainId: item.id || 0,
|
|
|
- platformType: item.platformType || '10',
|
|
|
- }
|
|
|
- }),
|
|
|
+ const [err]: ToResponse = await to(
|
|
|
+ cellAssignApi.create({
|
|
|
+ assignList: arr.map((item: any) => {
|
|
|
+ return {
|
|
|
+ appointId: item.id,
|
|
|
+ resId: item.resId,
|
|
|
+ location: item.location,
|
|
|
+ replaceId: item.replaceId,
|
|
|
+ mainId: item.id || 0,
|
|
|
+ platformType: item.platformType || '10',
|
|
|
+ }
|
|
|
}),
|
|
|
- )
|
|
|
- if (err) return
|
|
|
- showToast({ message: '操作成功', type: 'success' })
|
|
|
- emit('refresh')
|
|
|
- closeDialog()
|
|
|
+ }),
|
|
|
+ )
|
|
|
+ if (err) return
|
|
|
+ showToast({ message: '操作成功', type: 'success' })
|
|
|
+ emit('refresh')
|
|
|
+ closeDialog()
|
|
|
+}
|
|
|
+const onDetail = (val: number) => {
|
|
|
+ detailsDialog.value.openDialog('get', val)
|
|
|
+}
|
|
|
+// 分配
|
|
|
+const onAllocate = (pos: any) => {
|
|
|
+ if (state.active < 0) {
|
|
|
+ showToast({ message: '请先选择一个待分配人员', type: 'text' })
|
|
|
+ return
|
|
|
}
|
|
|
- const onDetail = (val: number) => {
|
|
|
- detailsDialog.value.openDialog('get', val)
|
|
|
+ const activeObj = state.confirmList[state.active]
|
|
|
+ if (activeObj.resId) {
|
|
|
+ showToast({ message: '该人员已分配房间,如需调整请先取消当前分配', type: 'text' })
|
|
|
+ return
|
|
|
}
|
|
|
- // 分配
|
|
|
- const onAllocate = (pos: any) => {
|
|
|
- if (state.active < 0) {
|
|
|
- showToast({ message: '请先选择一个待分配人员', type: 'text' })
|
|
|
- return
|
|
|
- }
|
|
|
- const activeObj = state.confirmList[state.active]
|
|
|
- if (activeObj.resId) {
|
|
|
- showToast({ message: '该人员已分配房间,如需调整请先取消当前分配', type: 'text' })
|
|
|
- return
|
|
|
- }
|
|
|
- const room = state.resourceList.find((item: any) => item.id == curSelectedResourceId.value)
|
|
|
- if (!room) {
|
|
|
- showToast({ message: '请选择资源房间', type: 'text' })
|
|
|
- return
|
|
|
- }
|
|
|
- if (room.resClass != activeObj.cellSourceType) {
|
|
|
- showToast({ message: '请选择正确的资源', type: 'text' })
|
|
|
- return
|
|
|
- }
|
|
|
- activeObj.resId = room.id
|
|
|
- activeObj.resName = room.resName
|
|
|
- activeObj.location = pos.location
|
|
|
- activeObj.replaceId = pos.id
|
|
|
- const user = confirmList.value.find((item: any) => item.id == activeObj.id)
|
|
|
- user.resId = room.id
|
|
|
- user.resName = room.resName
|
|
|
- user.location = pos.location
|
|
|
- user.replaceId = pos.id
|
|
|
- pos.userObj = { ...activeObj }
|
|
|
- const resource = resourceList.value.find((item: any) => item.id == room.id)
|
|
|
- const used = resource.usedList.find((item: any) => item.location == pos.location)
|
|
|
- used.userObj = { ...activeObj }
|
|
|
+ const room = state.resourceList.find((item: any) => item.id == curSelectedResourceId.value)
|
|
|
+ if (!room) {
|
|
|
+ showToast({ message: '请选择资源房间', type: 'text' })
|
|
|
+ return
|
|
|
}
|
|
|
- // 取消分配
|
|
|
- const cancelAllocate = (obj: any) => {
|
|
|
- if (!obj?.resId || !obj?.location) return
|
|
|
- const { resId, location } = obj
|
|
|
-
|
|
|
- const resetRoomUsage = (list: any[]) => {
|
|
|
- const room = list.find((item: any) => item.id === resId)
|
|
|
- if (!room?.usedList) return
|
|
|
- const used = room.usedList.find((i: any) => i.location === location)
|
|
|
- if (used) used.userObj = null
|
|
|
- }
|
|
|
-
|
|
|
- resetRoomUsage(resourceList.value)
|
|
|
- resetRoomUsage(state.resourceList)
|
|
|
+ if (room.resClass != activeObj.cellSourceType) {
|
|
|
+ showToast({ message: '请选择正确的资源', type: 'text' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ activeObj.resId = room.id
|
|
|
+ activeObj.resName = room.resName
|
|
|
+ activeObj.location = pos.location
|
|
|
+ activeObj.replaceId = pos.id
|
|
|
+ const user = confirmList.value.find((item: any) => item.id == activeObj.id)
|
|
|
+ user.resId = room.id
|
|
|
+ user.resName = room.resName
|
|
|
+ user.location = pos.location
|
|
|
+ user.replaceId = pos.id
|
|
|
+ pos.userObj = { ...activeObj }
|
|
|
+ const resource = resourceList.value.find((item: any) => item.id == room.id)
|
|
|
+ const used = resource.usedList.find((item: any) => item.location == pos.location)
|
|
|
+ used.userObj = { ...activeObj }
|
|
|
+}
|
|
|
+// 取消分配
|
|
|
+const cancelAllocate = (obj: any) => {
|
|
|
+ if (!obj?.resId || !obj?.location) return
|
|
|
+ const { resId, location } = obj
|
|
|
|
|
|
- if (Array.isArray(allocationSituationList.value) && allocationSituationList.value.length) {
|
|
|
- const usage = allocationSituationList.value.find((item: any) => item.location === location)
|
|
|
- if (usage) usage.userObj = null
|
|
|
- }
|
|
|
+ const resetRoomUsage = (list: any[]) => {
|
|
|
+ const room = list.find((item: any) => item.id === resId)
|
|
|
+ if (!room?.usedList) return
|
|
|
+ const used = room.usedList.find((i: any) => i.location === location)
|
|
|
+ if (used) used.userObj = null
|
|
|
+ }
|
|
|
|
|
|
- const user = confirmList.value.find((item) => item.id === obj.id)
|
|
|
- if (user) {
|
|
|
- user.resId = null
|
|
|
- user.resName = null
|
|
|
- user.location = null
|
|
|
- user.replaceId = null
|
|
|
- }
|
|
|
+ resetRoomUsage(resourceList.value)
|
|
|
+ resetRoomUsage(state.resourceList)
|
|
|
|
|
|
- obj.resId = null
|
|
|
- obj.resName = null
|
|
|
- obj.location = null
|
|
|
- obj.replaceId = null
|
|
|
+ if (Array.isArray(allocationSituationList.value) && allocationSituationList.value.length) {
|
|
|
+ const usage = allocationSituationList.value.find((item: any) => item.location === location)
|
|
|
+ if (usage) usage.userObj = null
|
|
|
+ }
|
|
|
|
|
|
- filterOutList(resClass.value)
|
|
|
+ const user = confirmList.value.find((item) => item.id === obj.id)
|
|
|
+ if (user) {
|
|
|
+ user.resId = null
|
|
|
+ user.resName = null
|
|
|
+ user.location = null
|
|
|
+ user.replaceId = null
|
|
|
}
|
|
|
- const getUsedClass = (row: any) => {
|
|
|
- if (row.assignStatus == '10') {
|
|
|
- // 空
|
|
|
- if (row.userObj) return 'empty-allocate'
|
|
|
- return 'empty'
|
|
|
- } else if (row.assignStatus == '40') {
|
|
|
- // 次月离室
|
|
|
- if (row.userObj) return 'leave-allocate'
|
|
|
- return 'leave'
|
|
|
- } else {
|
|
|
- // 占用20 已分配45
|
|
|
- return 'used'
|
|
|
- }
|
|
|
+
|
|
|
+ obj.resId = null
|
|
|
+ obj.resName = null
|
|
|
+ obj.location = null
|
|
|
+ obj.replaceId = null
|
|
|
+
|
|
|
+ filterOutList(resClass.value)
|
|
|
+}
|
|
|
+const getUsedClass = (row: any) => {
|
|
|
+ if (row.assignStatus == '10') {
|
|
|
+ // 空
|
|
|
+ if (row.userObj) return 'empty-allocate'
|
|
|
+ return 'empty'
|
|
|
+ } else if (row.assignStatus == '40') {
|
|
|
+ // 次月离室
|
|
|
+ if (row.userObj) return 'leave-allocate'
|
|
|
+ return 'leave'
|
|
|
+ } else {
|
|
|
+ // 占用20 已分配45
|
|
|
+ return 'used'
|
|
|
}
|
|
|
- // 暴露变量
|
|
|
- defineExpose({
|
|
|
- openDialog,
|
|
|
- })
|
|
|
+}
|
|
|
+// 暴露变量
|
|
|
+defineExpose({
|
|
|
+ openDialog,
|
|
|
+})
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
- .allocate-popup-container {
|
|
|
- .allocate-popup {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- height: 100%;
|
|
|
- padding: 16px;
|
|
|
- box-sizing: border-box;
|
|
|
+.allocate-popup-container {
|
|
|
+ .allocate-popup {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+ padding: 16px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .popup-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: flex-start;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 16px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+
|
|
|
+ .popup-title {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #111827;
|
|
|
}
|
|
|
- .popup-header {
|
|
|
+
|
|
|
+ .popup-controls {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: flex-start;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
flex-wrap: wrap;
|
|
|
- gap: 16px;
|
|
|
- margin-bottom: 16px;
|
|
|
- .popup-title {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: 600;
|
|
|
- color: #111827;
|
|
|
- }
|
|
|
- .popup-controls {
|
|
|
+
|
|
|
+ .group-selector {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- gap: 12px;
|
|
|
- flex-wrap: wrap;
|
|
|
- .group-selector {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
- padding: 6px 12px;
|
|
|
- background: #ffffff;
|
|
|
- border-radius: 999px;
|
|
|
- border: 1px solid #e5e7ef;
|
|
|
- box-shadow: 0 2px 6px rgba(148, 163, 184, 0.15);
|
|
|
- cursor: pointer;
|
|
|
- flex: 1;
|
|
|
- .label {
|
|
|
- width: 100px;
|
|
|
- font-size: 13px;
|
|
|
- color: #4b5563;
|
|
|
- font-weight: 500;
|
|
|
- }
|
|
|
- :deep(.van-field) {
|
|
|
- padding: 0;
|
|
|
- min-width: 120px;
|
|
|
- .van-field__control {
|
|
|
- font-size: 13px;
|
|
|
- color: #1f2937;
|
|
|
- }
|
|
|
- .van-field__control--right {
|
|
|
- text-align: right;
|
|
|
- }
|
|
|
- .van-field__right-icon {
|
|
|
- color: #2563eb;
|
|
|
- }
|
|
|
- }
|
|
|
+ gap: 10px;
|
|
|
+ padding: 6px 12px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 999px;
|
|
|
+ border: 1px solid #e5e7ef;
|
|
|
+ box-shadow: 0 2px 6px rgba(148, 163, 184, 0.15);
|
|
|
+ cursor: pointer;
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ .label {
|
|
|
+ width: 100px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #4b5563;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
- .type-radio-group {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
- padding: 6px 10px;
|
|
|
- background: #eef2ff;
|
|
|
- border-radius: 999px;
|
|
|
- .van-radio__icon {
|
|
|
- display: none;
|
|
|
- }
|
|
|
- .van-radio__label {
|
|
|
- color: #374151;
|
|
|
+
|
|
|
+ :deep(.van-field) {
|
|
|
+ padding: 0;
|
|
|
+ min-width: 120px;
|
|
|
+
|
|
|
+ .van-field__control {
|
|
|
font-size: 13px;
|
|
|
+ color: #1f2937;
|
|
|
}
|
|
|
- .van-radio--horizontal {
|
|
|
- padding: 0 6px;
|
|
|
+
|
|
|
+ .van-field__control--right {
|
|
|
+ text-align: right;
|
|
|
}
|
|
|
- .van-radio--horizontal.van-radio--checked .van-radio__label {
|
|
|
+
|
|
|
+ .van-field__right-icon {
|
|
|
color: #2563eb;
|
|
|
- font-weight: 600;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- .popup-body {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 16px;
|
|
|
- overflow-y: auto;
|
|
|
- padding-bottom: 16px;
|
|
|
- }
|
|
|
- .card {
|
|
|
- background: #fff;
|
|
|
- border-radius: 12px;
|
|
|
- padding: 16px;
|
|
|
- box-shadow: 0 6px 18px rgba(15, 23, 42, 0.08);
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 12px;
|
|
|
- .info-banner {
|
|
|
- padding: 10px 14px;
|
|
|
- border-radius: 8px;
|
|
|
- font-size: 15px;
|
|
|
- font-weight: 600;
|
|
|
- &.warning {
|
|
|
- background: linear-gradient(90deg, rgba(252, 211, 77, 0.2), rgba(253, 230, 138, 0.5));
|
|
|
- color: #b45309;
|
|
|
+
|
|
|
+ .type-radio-group {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 6px 10px;
|
|
|
+ background: #eef2ff;
|
|
|
+ border-radius: 999px;
|
|
|
+
|
|
|
+ .van-radio__icon {
|
|
|
+ display: none;
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
- .confirm-card {
|
|
|
- ul {
|
|
|
- max-height: 420px;
|
|
|
- overflow-y: auto;
|
|
|
- padding-right: 4px;
|
|
|
- &::-webkit-scrollbar {
|
|
|
- width: 6px;
|
|
|
+
|
|
|
+ .van-radio__label {
|
|
|
+ color: #374151;
|
|
|
+ font-size: 13px;
|
|
|
}
|
|
|
- &::-webkit-scrollbar-thumb {
|
|
|
- background: rgba(156, 163, 175, 0.4);
|
|
|
- border-radius: 999px;
|
|
|
+
|
|
|
+ .van-radio--horizontal {
|
|
|
+ padding: 0 6px;
|
|
|
}
|
|
|
- li {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- justify-content: space-between;
|
|
|
- gap: 12px;
|
|
|
- padding: 12px;
|
|
|
- border: 1px solid #e5e7eb;
|
|
|
- border-radius: 10px;
|
|
|
- transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
|
- cursor: pointer;
|
|
|
- & + li {
|
|
|
- margin-top: 10px;
|
|
|
- }
|
|
|
- &.active {
|
|
|
- border-color: #93c5fd;
|
|
|
- box-shadow: 0 10px 20px rgba(59, 130, 246, 0.08);
|
|
|
- }
|
|
|
- .text {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 6px;
|
|
|
- p {
|
|
|
- margin: 0;
|
|
|
- color: #374151;
|
|
|
- font-size: 14px;
|
|
|
- line-height: 1.4;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- }
|
|
|
- .assign-room {
|
|
|
- color: #2563eb;
|
|
|
- font-weight: 600;
|
|
|
- }
|
|
|
- }
|
|
|
- .btns {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 8px;
|
|
|
- justify-content: flex-end;
|
|
|
- .link-btn {
|
|
|
- padding: 6px 12px;
|
|
|
- border-radius: 999px;
|
|
|
- border: 1px solid transparent;
|
|
|
- background: #eff6ff;
|
|
|
- font-size: 13px;
|
|
|
- font-weight: 500;
|
|
|
- color: #1d4ed8;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.2s ease;
|
|
|
- line-height: 1;
|
|
|
- &:hover {
|
|
|
- background: #dbeafe;
|
|
|
- color: #1e40af;
|
|
|
- box-shadow: 0 4px 12px rgba(29, 78, 216, 0.25);
|
|
|
- }
|
|
|
- &.danger {
|
|
|
- background: #fee2e2;
|
|
|
- color: #dc2626;
|
|
|
- &:hover {
|
|
|
- background: #fecaca;
|
|
|
- color: #b91c1c;
|
|
|
- box-shadow: 0 4px 12px rgba(220, 38, 38, 0.25);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
+ .van-radio--horizontal.van-radio--checked .van-radio__label {
|
|
|
+ color: #2563eb;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- .resource-card {
|
|
|
- .van-empty {
|
|
|
- padding: 24px 0;
|
|
|
- .van-empty__description {
|
|
|
- color: #6b7280;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ .popup-body {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16px;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-bottom: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 16px;
|
|
|
+ box-shadow: 0 6px 18px rgba(15, 23, 42, 0.08);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+
|
|
|
+ .info-banner {
|
|
|
+ padding: 10px 14px;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+
|
|
|
+ &.warning {
|
|
|
+ background: linear-gradient(90deg, rgba(252, 211, 77, 0.2), rgba(253, 230, 138, 0.5));
|
|
|
+ color: #b45309;
|
|
|
}
|
|
|
- .resource-grid {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
|
- gap: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .confirm-card {
|
|
|
+ ul {
|
|
|
+ max-height: 420px;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-right: 4px;
|
|
|
+
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
}
|
|
|
- .resource-item {
|
|
|
- background: #f9fafb;
|
|
|
- border-radius: 10px;
|
|
|
- padding: 16px;
|
|
|
- border: 1px solid transparent;
|
|
|
+
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ background: rgba(156, 163, 175, 0.4);
|
|
|
+ border-radius: 999px;
|
|
|
+ }
|
|
|
+
|
|
|
+ li {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 10px;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 12px;
|
|
|
+ padding: 12px;
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
+ border-radius: 10px;
|
|
|
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
|
cursor: pointer;
|
|
|
- transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
|
|
- &:hover {
|
|
|
- transform: translateY(-2px);
|
|
|
- box-shadow: 0 10px 20px rgba(15, 23, 42, 0.12);
|
|
|
+
|
|
|
+ &+li {
|
|
|
+ margin-top: 10px;
|
|
|
}
|
|
|
+
|
|
|
&.active {
|
|
|
- border-color: #60a5fa;
|
|
|
- box-shadow: 0 8px 18px rgba(59, 130, 246, 0.16);
|
|
|
+ border-color: #93c5fd;
|
|
|
+ box-shadow: 0 10px 20px rgba(59, 130, 246, 0.08);
|
|
|
}
|
|
|
- .resource-header {
|
|
|
+
|
|
|
+ .text {
|
|
|
+ flex: 1;
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
- .resource-name {
|
|
|
- font-size: 16px;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 6px;
|
|
|
+
|
|
|
+ p {
|
|
|
+ margin: 0;
|
|
|
+ color: #374151;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.4;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+
|
|
|
+ .assign-room {
|
|
|
+ color: #2563eb;
|
|
|
font-weight: 600;
|
|
|
- color: #111827;
|
|
|
}
|
|
|
}
|
|
|
- .resource-location {
|
|
|
- color: #6b7280;
|
|
|
- font-size: 13px;
|
|
|
- }
|
|
|
- .resource-footer {
|
|
|
+
|
|
|
+ .btns {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- .resource-usage {
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 600;
|
|
|
- color: #111827;
|
|
|
- }
|
|
|
- .usage-dots {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 6px;
|
|
|
- row-gap: 6px;
|
|
|
- list-style: none;
|
|
|
- padding: 0;
|
|
|
- margin: 0;
|
|
|
- max-width: 120px;
|
|
|
- justify-content: flex-end;
|
|
|
- li {
|
|
|
- width: 10px;
|
|
|
- height: 10px;
|
|
|
- border-radius: 50%;
|
|
|
- background: #86efac;
|
|
|
- &.used {
|
|
|
- background: #f87171;
|
|
|
- }
|
|
|
- &.empty-allocate {
|
|
|
- background: linear-gradient(90deg, #86efac 0%, #86efac 50%, #2563eb 50%, #2563eb 100%);
|
|
|
- }
|
|
|
- &.leave {
|
|
|
- background: #fb923c;
|
|
|
- }
|
|
|
- &.leave-allocate {
|
|
|
- background: linear-gradient(90deg, #fb923c 0%, #fb923c 50%, #2563eb 50%, #2563eb 100%);
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 8px;
|
|
|
+ justify-content: flex-end;
|
|
|
+
|
|
|
+ .link-btn {
|
|
|
+ padding: 6px 12px;
|
|
|
+ border-radius: 999px;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ background: #eff6ff;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #1d4ed8;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+ line-height: 1;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #dbeafe;
|
|
|
+ color: #1e40af;
|
|
|
+ box-shadow: 0 4px 12px rgba(29, 78, 216, 0.25);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.danger {
|
|
|
+ background: #fee2e2;
|
|
|
+ color: #dc2626;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #fecaca;
|
|
|
+ color: #b91c1c;
|
|
|
+ box-shadow: 0 4px 12px rgba(220, 38, 38, 0.25);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- .usage-card {
|
|
|
- .usage-list {
|
|
|
- max-height: 360px;
|
|
|
- overflow-y: auto;
|
|
|
- padding-right: 4px;
|
|
|
- &::-webkit-scrollbar {
|
|
|
- width: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-card {
|
|
|
+ .van-empty {
|
|
|
+ padding: 24px 0;
|
|
|
+
|
|
|
+ .van-empty__description {
|
|
|
+ color: #6b7280;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-item {
|
|
|
+ background: #f9fafb;
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 16px;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ transform: translateY(-2px);
|
|
|
+ box-shadow: 0 10px 20px rgba(15, 23, 42, 0.12);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ border-color: #60a5fa;
|
|
|
+ box-shadow: 0 8px 18px rgba(59, 130, 246, 0.16);
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .resource-name {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #111827;
|
|
|
}
|
|
|
- &::-webkit-scrollbar-thumb {
|
|
|
- background: rgba(156, 163, 175, 0.4);
|
|
|
- border-radius: 999px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-location {
|
|
|
+ color: #6b7280;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-footer {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+
|
|
|
+ .resource-usage {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #111827;
|
|
|
}
|
|
|
- .position-choose {
|
|
|
+
|
|
|
+ .usage-dots {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 6px;
|
|
|
+ row-gap: 6px;
|
|
|
list-style: none;
|
|
|
padding: 0;
|
|
|
margin: 0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 8px;
|
|
|
+ max-width: 120px;
|
|
|
+ justify-content: flex-end;
|
|
|
+
|
|
|
li {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
- padding: 8px 10px;
|
|
|
- border: 1px solid #e5e7eb;
|
|
|
- border-radius: 8px;
|
|
|
- background: #f9fafb;
|
|
|
- i {
|
|
|
- width: 10px;
|
|
|
- height: 10px;
|
|
|
- border-radius: 50%;
|
|
|
- background: #86efac;
|
|
|
- &.used {
|
|
|
- background: #f87171;
|
|
|
- }
|
|
|
- &.empty-allocate {
|
|
|
- background: linear-gradient(90deg, #86efac 0%, #86efac 50%, #2563eb 50%, #2563eb 100%);
|
|
|
- }
|
|
|
- &.leave {
|
|
|
- background: #fb923c;
|
|
|
- }
|
|
|
- &.leave-allocate {
|
|
|
- background: linear-gradient(90deg, #fb923c 0%, #fb923c 50%, #2563eb 50%, #2563eb 100%);
|
|
|
- }
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #86efac;
|
|
|
+
|
|
|
+ &.used {
|
|
|
+ background: #f87171;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.empty-allocate {
|
|
|
+ background: linear-gradient(90deg, #86efac 0%, #86efac 50%, #2563eb 50%, #2563eb 100%);
|
|
|
}
|
|
|
- .txt-flex {
|
|
|
- flex: 1;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- color: #374151;
|
|
|
- font-size: 14px;
|
|
|
+
|
|
|
+ &.leave {
|
|
|
+ background: #fb923c;
|
|
|
}
|
|
|
- .van-button {
|
|
|
- min-width: 64px;
|
|
|
+
|
|
|
+ &.leave-allocate {
|
|
|
+ background: linear-gradient(90deg, #fb923c 0%, #fb923c 50%, #2563eb 50%, #2563eb 100%);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- .popup-footer {
|
|
|
- display: flex;
|
|
|
- gap: 12px;
|
|
|
- margin-top: 16px;
|
|
|
- .van-button {
|
|
|
- height: 44px;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ .usage-card {
|
|
|
+ .usage-list {
|
|
|
+ max-height: 360px;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding-right: 4px;
|
|
|
+
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ background: rgba(156, 163, 175, 0.4);
|
|
|
+ border-radius: 999px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .position-choose {
|
|
|
+ list-style: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ li {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 8px 10px;
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #f9fafb;
|
|
|
+
|
|
|
+ i {
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #86efac;
|
|
|
+
|
|
|
+ &.used {
|
|
|
+ background: #f87171;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.empty-allocate {
|
|
|
+ background: linear-gradient(90deg, #86efac 0%, #86efac 50%, #2563eb 50%, #2563eb 100%);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.leave {
|
|
|
+ background: #fb923c;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.leave-allocate {
|
|
|
+ background: linear-gradient(90deg, #fb923c 0%, #fb923c 50%, #2563eb 50%, #2563eb 100%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .txt-flex {
|
|
|
+ flex: 1;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ color: #374151;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .van-button {
|
|
|
+ min-width: 64px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- @media (min-width: 1024px) {
|
|
|
- .allocate-popup-container {
|
|
|
- .popup-body {
|
|
|
- flex-direction: row;
|
|
|
- .confirm-card {
|
|
|
- flex: 0 0 300px;
|
|
|
- }
|
|
|
- .resource-card {
|
|
|
- flex: 1;
|
|
|
- }
|
|
|
- .usage-card {
|
|
|
- flex: 0 0 280px;
|
|
|
- }
|
|
|
+
|
|
|
+ .popup-footer {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ margin-top: 16px;
|
|
|
+
|
|
|
+ .van-button {
|
|
|
+ height: 44px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (min-width: 1024px) {
|
|
|
+ .allocate-popup-container {
|
|
|
+ .popup-body {
|
|
|
+ flex-direction: row;
|
|
|
+
|
|
|
+ .confirm-card {
|
|
|
+ flex: 0 0 300px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .resource-card {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .usage-card {
|
|
|
+ flex: 0 0 280px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
</style>
|