index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. <template>
  2. <u-sticky class="shadow-default" bgColor="#fff" style="top: 0">
  3. <u-navbar :titleStyle="{ color: '#000' }" :autoBack="true" title="会议预约" :placeholder="true" :safeAreaInsetTop="true" bgColor="#fff">
  4. <template #left>
  5. <view class="u-navbar__content__left__item">
  6. <u-icon name="arrow-left" size="20" color="#000"></u-icon>
  7. </view>
  8. </template>
  9. <template #right>
  10. <view class="u-navbar__content__right__item">
  11. <u-icon name="more-dot-fill" size="19" color="#000"></u-icon>
  12. </view>
  13. </template>
  14. </u-navbar>
  15. <view class="flex plr10">
  16. <u--input
  17. style="width: 100%"
  18. v-model="form.meetingRoomName"
  19. placeholder="搜索会议室"
  20. prefixIcon="search"
  21. prefixIconStyle="font-size: 22px;color: #909399"
  22. customStyle="height:35px;background-color:#f5f6fa; "
  23. @confirm="init()"
  24. clearable
  25. ></u--input>
  26. </view>
  27. <view class="flex plr10" style="line-height: 20px">
  28. <view class="flex mtb-auto ptb10 nav" style="overflow-x: auto" @click="handlePopup(true, 'switchTime', {})">
  29. <view
  30. class="radius p5 mr10"
  31. :style="{
  32. color: proxy.$settingStore.themeColor.color,
  33. backgroundColor: `${proxy.$settingStore.themeColor.color}30`,
  34. }"
  35. >
  36. {{ proxy.$dayjs(form.date).format("MM月DD日") }}
  37. {{ weekData[proxy.$dayjs(form.date).format("d")] }}
  38. </view>
  39. </view>
  40. <view class="ml-auto mtb-auto pl10 nav" :style="{ color: proxy.$settingStore.themeColor.color }">重置</view>
  41. </view>
  42. </u-sticky>
  43. <oa-scroll
  44. customClass="record-container scroll-height"
  45. :isSticky="true"
  46. :customStyle="{
  47. //#ifdef APP-PLUS || MP-WEIXIN
  48. height: `calc(100vh - (44px + 35px + 50px + ${proxy.$settingStore.StatusBarHeight}))`,
  49. //#endif
  50. //#ifdef H5
  51. height: 'calc(100vh - (44px + 35px + 50px))',
  52. //#endif
  53. }"
  54. :pageSize="pageSize"
  55. :total="total"
  56. :refresherLoad="false"
  57. :refresherEnabled="true"
  58. :refresherDefaultStyle="'none'"
  59. :refresherThreshold="44"
  60. :refresherBackground="'#f5f6f7'"
  61. @refresh="refresh"
  62. :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
  63. >
  64. <template #default>
  65. <u-loading-page :loading="state.loading" fontSize="16" style="z-index: 99"></u-loading-page>
  66. <view class="content-area bg-white radius flex flex-wrap m10 p10" v-for="room in dataList" :key="room" @click="handlePopup(true, 'aboutMeeting', room)">
  67. <view class="mr10 mtb-auto">
  68. <u-image v-if="room.imgPath" :show-loading="true" :src="room.imgPath" width="50px" height="50px" radius="5px"></u-image>
  69. <u-image v-else :show-loading="true" src="@/static/images/defaultImg.jpg" width="50px" height="50px" radius="5px"></u-image>
  70. </view>
  71. <view class="mtb-auto">
  72. <view class="font16 text-black mb5">{{ room.roomName }}</view>
  73. <view class="font12 text-gray">可容纳{{ room.capacity || 0 }}人</view>
  74. </view>
  75. <view class="mt10" style="width: 100%">
  76. <timeSlot :currentDay="form.date" :aboutTimeData="room.dmMeetingList" :activeColor="proxy.$settingStore.themeColor.color" />
  77. </view>
  78. </view>
  79. </template>
  80. </oa-scroll>
  81. <u-popup :show="popup.show" mode="bottom" bgColor="#fff" :round="10" @close="popup.show = false">
  82. <view
  83. :style="{
  84. borderTopLeftRadius: '10px',
  85. borderTopRightRadius: '10px',
  86. overflow: 'hidden',
  87. }"
  88. >
  89. <oa-calendar v-if="popup.type === 'switchTime'" :date="form.date" :showMonth="true" @change="calendarChange" @monthSwitch="calendarMonthSwitch">
  90. <template #headerRight> </template>
  91. </oa-calendar>
  92. <view v-if="popup.type === 'aboutMeeting'">
  93. <view class="flex p15 font16">
  94. <view class="mtb-auto"> {{ popup.list.roomName }}</view>
  95. <view class="mtb-auto ml-auto" @click="sheet.show = true">
  96. <u-icon name="info-circle" size="16" label="更多" labelSize="14" labelColor="#333" color="#333"></u-icon>
  97. </view>
  98. </view>
  99. <u-gap height="10" bgColor="#f5f6f7"></u-gap>
  100. <u-checkbox-group v-model="checkboxValue" placement="column" shape="circle" :borderBottom="true" @change="checkboxChange" style="height: 42vh; overflow: auto">
  101. <view v-for="(item, index) in checkboxList" :key="index">
  102. <u-checkbox
  103. :customStyle="{ padding: '15px', margin: '0', backgroundColor: `${item.isDisabledColor}30` }"
  104. :label="item.timeSlot"
  105. :name="item.startTime"
  106. :disabled="item.isDisabled || item.isAbout === '已预约'"
  107. :activeColor="proxy.$settingStore.themeColor.color"
  108. >
  109. <template #label>
  110. <view class="font15 mtb-auto" :style="{ color: item.isDisabled || item.isAbout === '已预约' ? '#c8c9cc' : '#333333' }"> {{ item.timeSlot }}</view>
  111. <view class="font15 mtb-auto ml-auto" :style="{ color: item.isDisabled || item.isAbout === '已预约' ? '#c8c9cc' : '#333333' }"> {{ item.isAbout }}</view>
  112. </template>
  113. </u-checkbox>
  114. </view>
  115. </u-checkbox-group>
  116. <u-gap height="10" bgColor="#f5f6f7"></u-gap>
  117. <view class="p10" style="overflow: hidden">
  118. <u-button type="primary" @click="handleSubmit('下一步')" text="下一步" style="width: 100px; float: right"></u-button>
  119. </view>
  120. </view>
  121. </view>
  122. </u-popup>
  123. <u-action-sheet
  124. :actions="sheet.actions"
  125. :show="sheet.show"
  126. cancelText="取消"
  127. :round="10"
  128. :wrapMaxHeight="'50vh'"
  129. :closeOnClickOverlay="true"
  130. :safeAreaInsetBottom="true"
  131. @close="sheet.show = false"
  132. @select="handleSheet"
  133. ></u-action-sheet>
  134. </template>
  135. <script setup>
  136. /*----------------------------------依赖引入-----------------------------------*/
  137. import { onLoad, onShow, onReady, onHide, onLaunch, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
  138. import { ref, reactive, computed, getCurrentInstance, toRefs, inject } from "vue";
  139. /*----------------------------------接口引入-----------------------------------*/
  140. import { MeetingRoomList, MeetingRoomReservationList, control } from "@/api/business/meeting.js";
  141. /*----------------------------------组件引入-----------------------------------*/
  142. import timeSlot from "./components/timeSlot.vue";
  143. /*----------------------------------store引入-----------------------------------*/
  144. import { useStores, systemStores } from "@/store/modules/index";
  145. /*----------------------------------公共方法引入-----------------------------------*/
  146. import { storageSystem } from "@/utils/storage"; // 公共方法引用
  147. /*----------------------------------公共变量-----------------------------------*/
  148. const { proxy } = getCurrentInstance();
  149. const useStore = useStores();
  150. const systemStore = systemStores();
  151. /*----------------------------------变量声明-----------------------------------*/
  152. const state = reactive({
  153. loading: false,
  154. dataList: [],
  155. pageSize: 20,
  156. total: 0,
  157. form: {
  158. date: proxy.$dayjs().format("YYYY-MM-DD"),
  159. meetingRoomName: "",
  160. },
  161. popup: {
  162. show: false,
  163. type: "",
  164. list: {},
  165. },
  166. sheet: {
  167. show: false,
  168. title: "",
  169. actions: [
  170. {
  171. name: "更多",
  172. fontSize: "16",
  173. disabled: true,
  174. },
  175. {
  176. name: "门禁开门",
  177. fontSize: "16",
  178. type: "meeting-room",
  179. },
  180. {
  181. name: "会议室详情",
  182. fontSize: "16",
  183. type: "meeting-details",
  184. },
  185. ],
  186. },
  187. weekData: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
  188. checkboxValue: [],
  189. checkboxList: [],
  190. });
  191. const { loading, dataList, pageSize, total, form, popup, sheet, weekData, checkboxValue, checkboxList } = toRefs(state);
  192. /** 初始化 */
  193. function init() {
  194. state.checkboxValue = [];
  195. state.checkboxList = [];
  196. state.loading = true;
  197. MeetingRoomReservationList({
  198. date: state.form.date + " 00:00:00",
  199. meetingRoomName: state.form.meetingRoomName,
  200. })
  201. .then((requset) => {
  202. if (requset.status === "SUCCESS") {
  203. state.dataList = requset.data;
  204. state.total = requset.data.length;
  205. state.loading = false;
  206. }
  207. })
  208. .catch((err) => {
  209. state.loading = false;
  210. });
  211. state.checkboxList = getAllTimesDay(state.form.date, 30);
  212. }
  213. /** 获取当天时间 */
  214. function getAllTimesDay(day, min) {
  215. let defaultList = [];
  216. // 获取当天开始的时间
  217. const startOfDay = proxy.$dayjs(day).startOf("day");
  218. const endOfDay = proxy.$dayjs(day).endOf("day");
  219. // 循环半小时直到当天结束
  220. for (let currentTime = startOfDay; currentTime.isBefore(endOfDay); currentTime = currentTime.add(min, "minute")) {
  221. let isAfter = currentTime.add(min, "minute").isAfter(endOfDay); //当前时间是否在结束时间之后(true|false)
  222. let startTime = currentTime.add(0, "minute").format("YYYY-MM-DD HH:mm:ss"); //获取开始时间
  223. let endTime = isAfter ? endOfDay.format("YYYY-MM-DD HH:mm:ss") : currentTime.add(min, "minute").format("YYYY-MM-DD HH:mm:ss"); //获取结束时间
  224. let timeSlot = proxy.$dayjs(startTime).format("HH:mm") + " - " + proxy.$dayjs(endTime).format("HH:mm"); //获取开始时间和结束时间“时、分”
  225. const array = {
  226. startTime: startTime,
  227. endTime: endTime,
  228. timeSlot: timeSlot,
  229. isDisabled: false,
  230. isAbout: "",
  231. isDisabledColor: "#FFFFFF",
  232. isDisabledFontColor: "#333333",
  233. }; //此返回值(不可删除)可叠加
  234. //判断当前时间是否相同或在其之后
  235. if (proxy.$dayjs().isSameOrAfter(startTime)) {
  236. array.isAbout = "不可预约";
  237. array.isDisabled = true;
  238. }
  239. defaultList.push(array);
  240. }
  241. return defaultList;
  242. }
  243. /** 复选框改变事件 */
  244. function checkboxChange(e, index) {
  245. if (e.length > 1) {
  246. const startOfDay = proxy.$dayjs(e[0]);
  247. const endOfDay = proxy.$dayjs(e[e.length - 1]);
  248. for (let currentTime = startOfDay; currentTime.isBefore(endOfDay); currentTime = currentTime.add(30, "minute")) {
  249. if (!e.includes(currentTime.format("YYYY-MM-DD HH:mm:ss"))) {
  250. e.push(currentTime.format("YYYY-MM-DD HH:mm:ss"));
  251. }
  252. }
  253. }
  254. state.checkboxValue = e.sort((a, b) => new Date(`${proxy.$dayjs(a).format("YYYY-MM-DD HH:mm:ss")}`) - new Date(`${proxy.$dayjs(b).format("YYYY-MM-DD HH:mm:ss")}`));
  255. }
  256. /** 点击预约 */
  257. function handleSubmit() {
  258. if (!state.checkboxValue.length) {
  259. proxy.$modal.msg("请先选择时间");
  260. return false;
  261. }
  262. systemStore.meetingList.form = {
  263. roomId: state.popup.list.roomId, //房间Id
  264. roomName: state.popup.list.roomName, //会议室名称
  265. startDate: state.checkboxValue[0], //会议开始时间
  266. endDate: state.checkboxValue[state.checkboxValue.length - 1], //会议结束时间
  267. meetingName: useStore.nickName + "预约的会议", //会议名称
  268. initiatorUser: {
  269. contacts: useStore.phonenumber, //联系方式
  270. deptId: useStore.deptId,
  271. email: useStore.email,
  272. id: useStore.userId,
  273. isApprover: false,
  274. name: useStore.nickName, //验证人名称
  275. sex: useStore.sex,
  276. }, //发起人信息
  277. meetingDescribe: "", //会议介绍
  278. users: [], //参会人信息
  279. meetingMode: 0, //会议模式
  280. sendType: ["站内信"], //通知类型(短信)
  281. remark: "", //备注
  282. room: state.popup.list, //会议室信息
  283. meetingFileList: [], //会议文件信息
  284. };
  285. proxy.$tab.navigateTo(`/pages/business/common/meeting/new/index`);
  286. state.popup.show = false;
  287. }
  288. /** 实时保存填写数据 */
  289. function realTimeSaving() {
  290. if (!state.form.id) {
  291. state.saveTime = proxy.$time.formatterDate(new Date(), "hh:mm");
  292. storageSystem.set("project", state);
  293. }
  294. }
  295. /** 日历日期改变事件 */
  296. function calendarChange(e) {
  297. state.form.date = e.fulldate;
  298. init();
  299. }
  300. /** 日历月份选择事件 */
  301. function calendarMonthSwitch(e) {
  302. console.log(e);
  303. }
  304. /** 操作菜单 */
  305. function handleSheet(e) {
  306. if (e.type == "meeting-details") {
  307. proxy.$tab.navigateTo(`/pages/business/common/meeting/detailed/index?roomId=${state.popup.list.roomId}`).then(() => {});
  308. } else if (e.type == "meeting-room") {
  309. openDoor();
  310. }
  311. }
  312. /**
  313. * @门禁开门
  314. */
  315. function openDoor() {
  316. control({
  317. commandStr: JSON.stringify({ method: "control", params: { device_id: "223212768", command: 2 } }),
  318. })
  319. .then((item2) => {
  320. proxy.$modal.msg("开门成功");
  321. })
  322. .catch((err) => {
  323. console.log(err);
  324. });
  325. }
  326. /** 操作弹窗 */
  327. function handlePopup(show, type, list) {
  328. state.popup.show = show;
  329. state.popup.type = type;
  330. state.popup.list = list;
  331. if (type === "aboutMeeting") {
  332. list.dmMeetingList.forEach((e) => {
  333. let startTime = proxy.$dayjs(e.startDate).add(0, "minute").format("YYYY-MM-DD HH:mm:ss");
  334. let endTimeNum = e.endDate.indexOf("59") != -1 ? -29.59 : -30;
  335. let endTime = proxy.$dayjs(e.endDate).add(endTimeNum, "minute").format("YYYY-MM-DD HH:mm:ss");
  336. state.checkboxList.forEach((f) => {
  337. if (proxy.$dayjs(f.startTime).isBetween(startTime, endTime, null, "[]")) {
  338. f.isDisabledColor = proxy.$settingStore.themeColor.color;
  339. f.isDisabledFontColor = "#FFFFFF";
  340. f.isAbout = "已预约";
  341. }
  342. });
  343. });
  344. }
  345. }
  346. /**
  347. * @scrollView刷新数据
  348. */
  349. function refresh() {
  350. init();
  351. }
  352. onReady(() => {});
  353. onShow(() => {
  354. //调用系统主题颜色
  355. proxy.$settingStore.systemThemeColor([1]);
  356. init();
  357. });
  358. onLoad((options) => {});
  359. onUnload(() => {});
  360. </script>
  361. <style lang="scss" scoped>
  362. .content-area {
  363. color: #000000;
  364. }
  365. </style>