index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <template>
  2. <ContentWrap>
  3. <div class="flex-between">
  4. <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
  5. <!-- <el-form-item label="机构">
  6. <el-select
  7. class="!w-240px mr5 ml5"
  8. v-model="queryParams.tenantId"
  9. @change="changeMonth"
  10. clearable
  11. >
  12. <el-option
  13. v-for="item in tenantList"
  14. :key="item.id"
  15. :value="item.id"
  16. :label="item.name"
  17. />
  18. </el-select>
  19. </el-form-item> -->
  20. <TenantSelect v-model="queryParams.tenantIds" placeholder="请选择机构名称" prop="tenantIds" @change="changeMonth" />
  21. <el-form-item label="活动月份" class="!w-240px">
  22. <TgDatePicker type="month" v-model="queryParams.month" @change="changeMonth" />
  23. </el-form-item>
  24. <el-form-item label="" class="!w-240px">
  25. <el-button type="warning" @click="exportPort">导 出</el-button>
  26. </el-form-item>
  27. </el-form>
  28. </div>
  29. </ContentWrap>
  30. <ContentWrap>
  31. <el-scrollbar>
  32. <el-calendar id="monthlyCalendar" v-model="calendarMonth">
  33. <template #date-cell="{ data }">
  34. <div :class="[data.isSelected ? 'is-selected' : '', 'flex-between']">
  35. <span>{{ data.day.split('-').slice(1).join('-') }}</span>
  36. <div :class="comAction.isFestival(data) ? 'festival-holiday' : ''"
  37. ><span v-html="comAction.solarToLunar(data)"></span
  38. ></div>
  39. </div>
  40. <el-scrollbar height="220px" ref="containerRef">
  41. <div
  42. class="item"
  43. v-for="item in monthInfo[data.day.split('-').slice(1).join('-')]?.child"
  44. :key="item"
  45. @click="openForm(item, true)"
  46. >
  47. <div class="mt2">{{ item.activityTitle }}</div>
  48. <div class="mt1 text"
  49. ><Icon icon="ep:clock" /><span class="ml1"
  50. >{{ item.activityStartTime.split(' ')[1] }}-{{
  51. item.activityEndTime.split(' ')[1]
  52. }}</span
  53. ></div
  54. >
  55. <div class="mt1 text"
  56. ><Icon icon="ep:location-information" /><span class="ml1">{{
  57. item.activityAddress
  58. }}</span></div
  59. >
  60. </div>
  61. </el-scrollbar>
  62. </template>
  63. </el-calendar>
  64. </el-scrollbar>
  65. </ContentWrap>
  66. <Form ref="formRef" @success="getList" />
  67. </template>
  68. <script setup lang="ts">
  69. import { getMonthlyActivityByMonth } from '@/api/elderly/activity'
  70. import { getTenant } from '@/api/system/dept'
  71. import lunar from '@/utils/lunar'
  72. import Form from './Form.vue'
  73. import { formatTime } from '@/utils'
  74. import { formatDate } from '@/utils/formatTime'
  75. import { useUserStore } from '@/store/modules/user'
  76. import ExcelJS from 'exceljs'
  77. import { saveAs } from 'file-saver'
  78. import { getAccessToken } from '@/utils/auth'
  79. import { dayjs } from 'element-plus'
  80. const userStore = useUserStore()
  81. const formRef = ref()
  82. const openForm = (row: any = {}, detail: boolean = false) => {
  83. formRef.value.open(row.tenantId, row.activityId, detail)
  84. }
  85. const comAction = {
  86. // 是否节假日
  87. isFestival(slotData) {
  88. // console.log(slotData);
  89. let solarDayArr = slotData.day.split('-')
  90. let lunarDay: any = lunar.solar2lunar(solarDayArr[0], solarDayArr[1], solarDayArr[2])
  91. // 公历节日\农历节日\农历节气
  92. let festAndTerm: any = []
  93. festAndTerm.push(lunarDay.festival == null ? '' : ' ' + lunarDay.festival)
  94. festAndTerm.push(lunarDay.lunarFestival == null ? '' : '' + lunarDay.lunarFestival)
  95. festAndTerm.push(lunarDay.Term == null ? '' : '' + lunarDay.Term)
  96. festAndTerm = festAndTerm.join('')
  97. return festAndTerm != ''
  98. },
  99. // 公历转农历
  100. solarToLunar(slotData) {
  101. // console.log(slotData);
  102. let solarDayArr = slotData.day.split('-')
  103. let lunarDay: any = lunar.solar2lunar(solarDayArr[0], solarDayArr[1], solarDayArr[2])
  104. // 农历日期
  105. let lunarMD = lunarDay.IMonthCn + lunarDay.IDayCn
  106. // 公历节日\农历节日\农历节气
  107. let festAndTerm = ''
  108. festAndTerm += lunarDay.festival == null ? '' : lunarDay.festival + '<br />'
  109. festAndTerm += lunarDay.lunarFestival == null ? '' : lunarDay.lunarFestival + '<br />'
  110. festAndTerm += lunarDay.Term == null ? '' : lunarDay.Term + '<br />'
  111. return festAndTerm == '' ? lunarMD : festAndTerm
  112. }
  113. }
  114. onMounted(async () => {
  115. calendarMonth.value = formatTime(Date.now(), 'yyyy-MM')
  116. queryParams.month = calendarMonth.value
  117. // await getTenantList()
  118. getList()
  119. })
  120. const tenantList = ref<{ id: string; name: string }[]>([])
  121. const getTenantList = async () => {
  122. const res = await getTenant()
  123. tenantList.value = res
  124. // 如果只有一条数据就默认选中
  125. // if (res.length == 1) {
  126. // queryParams.tenantId = res[0].id
  127. // }
  128. }
  129. const exportPort = async () => {
  130. const params = new URLSearchParams()
  131. params.append('month', queryParams.month)
  132. queryParams.tenantIds.map(item => {
  133. params.append('tenantIds', item)
  134. })
  135. const listData = await getMonthlyActivityByMonth(params)
  136. const exportList = listData || []
  137. const workbook = new ExcelJS.Workbook()
  138. const worksheet = workbook.addWorksheet('月度活动')
  139. const activityTypeMap: Record<string, string> = {
  140. '1': '节日庆典',
  141. '2': '健康讲座',
  142. '3': '文艺活动',
  143. '4': '体育健身',
  144. '5': '志愿服务',
  145. '6': '其他'
  146. }
  147. const statusMap: Record<number, string> = {
  148. 0: '未开始',
  149. 1: '进行中',
  150. 2: '已结束'
  151. }
  152. worksheet.columns = [
  153. { header: '活动主题', key: 'activityTitle', width: 50 },
  154. { header: '活动类型', key: 'activityTypeText', width: 15 },
  155. { header: '活动日期', key: 'activityDate', width: 20 },
  156. { header: '活动开始时间', key: 'activityStartTime', width: 20 },
  157. { header: '活动结束时间', key: 'activityEndTime', width: 20 },
  158. { header: '活动地点', key: 'activityAddress', width: 30 },
  159. { header: '参与人数', key: 'number', width: 15 },
  160. { header: '报名开始时间', key: 'registrationStartTime', width: 20 },
  161. { header: '报名结束时间', key: 'registrationEndTime', width: 20 },
  162. { header: '状态', key: 'statusText', width: 15 },
  163. { header: '负责人', key: 'supervisorName', width: 15 },
  164. { header: '创建人', key: 'createdBy', width: 15 },
  165. { header: '活动说明', key: 'remarks', width: 60 }
  166. ]
  167. const headerRow = worksheet.getRow(1)
  168. headerRow.font = { bold: true, size: 12 }
  169. headerRow.fill = {
  170. type: 'pattern',
  171. pattern: 'solid',
  172. fgColor: { argb: 'FFE0E0E0' }
  173. }
  174. headerRow.alignment = { horizontal: 'center', vertical: 'middle' }
  175. for (let i = 0; i < exportList.length; i++) {
  176. const item = exportList[i]
  177. const row = worksheet.addRow({
  178. activityTitle: item.activityTitle,
  179. activityTypeText: activityTypeMap[item.activityType] || item.activityType,
  180. activityDate: item.activityDate,
  181. activityStartTime: item.activityStartTime,
  182. activityEndTime: item.activityEndTime,
  183. activityAddress: item.activityAddress,
  184. number: item.number,
  185. registrationStartTime: item.registrationStartTime,
  186. registrationEndTime: item.registrationEndTime,
  187. statusText: statusMap[item.status] || item.status,
  188. supervisorName: item.supervisorName,
  189. createdBy: item.createdBy,
  190. remarks: item.remarks
  191. })
  192. row.alignment = { vertical: 'top', wrapText: true }
  193. }
  194. const buffer = await workbook.xlsx.writeBuffer()
  195. const blob = new Blob([buffer], {
  196. type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  197. })
  198. saveAs(blob, `月度活动_${queryParams.month}_${dayjs().format('YYYY-MM-DD')}.xlsx`)
  199. }
  200. const calendarMonth = ref()
  201. const monthInfo = ref({})
  202. const queryParams = reactive({
  203. month: '',
  204. tenantIds: userStore.orgTenantId
  205. })
  206. const getList = async () => {
  207. const params = new URLSearchParams()
  208. params.append('month', queryParams.month)
  209. if(typeof queryParams.tenantIds == 'number' || typeof queryParams.tenantIds == 'string'){
  210. params.append('tenantIds', props.tId)
  211. }else{
  212. queryParams.tenantIds.map(item=>{
  213. params.append('tenantIds', item)
  214. })
  215. }
  216. const res = await getMonthlyActivityByMonth(params)
  217. let dataInfo = {}
  218. res.forEach((item) => {
  219. item.activityDate = formatDate(item.activityDate, 'MM-DD')
  220. item.activityStartTime = item.activityStartTime
  221. item.activityEndTime = item.activityEndTime
  222. let { activityDate } = item
  223. if (!dataInfo[activityDate]) {
  224. dataInfo[activityDate] = {
  225. activityDate,
  226. child: []
  227. }
  228. }
  229. dataInfo[activityDate].child.push(item)
  230. })
  231. monthInfo.value = dataInfo
  232. }
  233. // // 在 script setup 中添加
  234. // watch(calendarMonth, (newVal) => {
  235. // if (newVal) {
  236. // // formatDate 是你已经引入的工具函数,格式化为 'YYYY-MM'
  237. // queryParams.month = formatDate(newVal, 'YYYY-MM')
  238. // console.log(queryParams.month)
  239. // // 如果 formatDate 不合适,也可以手动格式化:
  240. // // queryParams.month = dayjs(newVal).format('YYYY-MM')
  241. // }
  242. // })
  243. const changeMonth = () => {
  244. calendarMonth.value = queryParams.month
  245. getList()
  246. }
  247. </script>
  248. <style lang="scss">
  249. .crown {
  250. width: 22px;
  251. margin-right: 5px;
  252. }
  253. #monthlyCalendar {
  254. min-width: 900px;
  255. .el-calendar__body {
  256. .el-calendar-table {
  257. border-collapse: separate;
  258. border-spacing: 15px;
  259. .el-calendar-table__row {
  260. width: 150px;
  261. height: 250px;
  262. .current {
  263. background-color: #f4f6f9;
  264. border-radius: 8px;
  265. &.is-today {
  266. background-color: var(--el-calendar-selected-bg-color);
  267. .item {
  268. color: #6f6d70;
  269. &:hover {
  270. background-color: var(--el-color-primary-light-7);
  271. color: #fff;
  272. }
  273. }
  274. }
  275. &.is-selected {
  276. background-color: var(--el-calendar-selected-bg-color);
  277. }
  278. }
  279. .next,
  280. .prev {
  281. background-color: #f6f6f6;
  282. border-radius: 8px;
  283. }
  284. }
  285. .el-scrollbar {
  286. .item {
  287. color: #6f6d70;
  288. box-sizing: border-box;
  289. font-size: 14px;
  290. padding-bottom: 3px;
  291. border-bottom: 1px solid #ddd;
  292. cursor: pointer;
  293. &:hover {
  294. background-color: var(--el-color-primary-light-7);
  295. color: #fff;
  296. }
  297. }
  298. .text {
  299. display: flex;
  300. align-items: center;
  301. overflow: hidden;
  302. white-space: nowrap;
  303. text-overflow: ellipsis;
  304. }
  305. }
  306. }
  307. }
  308. .f600 {
  309. font-weight: 600;
  310. }
  311. }
  312. .el-calendar-table td {
  313. border: none !important;
  314. }
  315. .el-calendar-table {
  316. thead {
  317. th {
  318. background-color: #f6f6f6;
  319. border-radius: 8px;
  320. margin: 5px;
  321. &:before {
  322. content: '星期';
  323. }
  324. }
  325. }
  326. .el-calendar-day {
  327. height: 100% !important;
  328. &:hover {
  329. cursor: auto;
  330. background-color: transparent;
  331. }
  332. }
  333. }
  334. .el-calendar__header {
  335. display: none;
  336. }
  337. </style>