index.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import { List, Popup, DatePicker, Popover, Field, Picker, } from 'vant';
  4. import request from '@/helpers/request';
  5. import { useRoute, useRouter } from 'vue-router';
  6. import OEmpty from '@/components/m-empty';
  7. import MWxTip from '@/components/m-wx-tip';
  8. import OSearch from '@/components/m-search';
  9. import positionIcon from './images/position_icon.png';
  10. import scIcon1 from './images/sc_icon1.png';
  11. import scIcon2 from './images/sc_icon2.png';
  12. import scIcon3 from './images/sc_icon3.png';
  13. import schoolIcon from './images/school_icon.png';
  14. import schoolIcon2 from './images/school_icon2.png';
  15. import searchIcon from './images/search_icon.png';
  16. import searchBtn from './images/search_btn.png';
  17. import tjnumIicon from './images/tjnum_icon.png';
  18. import totalBoxBg from './images/total_box_icon.png';
  19. import useWeChatShare from '@/hooks/useWeChatShare';
  20. import { browser } from '@/helpers/utils';
  21. import OFullRefresh from '@/components/m-full-refresh';
  22. import tbgIcon1 from './images/new_tbg_icon1.png';
  23. import tbgIcon2 from './images/new_tbg_icon2.png';
  24. import tbgIcon3 from './images/new_tbg_icon3.png';
  25. export default defineComponent({
  26. name: 'questionnaire-statistics',
  27. setup() {
  28. const route = useRoute();
  29. const router = useRouter();
  30. const tabName = ref('all');
  31. const forms = reactive({
  32. schoolName: '',
  33. id: route.query.id,
  34. // id: '1687275949971763202',
  35. yearStatus: false,
  36. schoolId: null,
  37. classList: [] as any,
  38. page: 1,
  39. rows: 20,
  40. isClick: false,
  41. tenantId: route.query.id,
  42. areaList: [] as any,
  43. areaColumns: [] as any,
  44. areaStatus: false,
  45. areaPopupShow: false,
  46. areaOptionIndex: [] as any,
  47. currentArea: null as any, // 当前的区域
  48. currentAreaInfo: null as any,
  49. schoolList: [] as any,
  50. totalInfo: {} as any,
  51. sortType: 'DESC' as any, // 排序方式,ASC(升序)/DESC(降序)
  52. sortField: 'totalNum', // totalNum: 总人数,supportNum:支持人数,supportRate:支持率
  53. areaIdx: 0 as any,
  54. });
  55. const refreshing = ref(false);
  56. const loading = ref(true);
  57. const finished = ref(false);
  58. const showContact = ref(false);
  59. const list = ref([]);
  60. const queryArea = async () => {
  61. try {
  62. const { data } = await request.get(
  63. `/edu-app/open/tenantInfo/getArea?tenantId=${forms.tenantId}`, {
  64. hideLoading: false,
  65. }
  66. );
  67. forms.areaList = data || []
  68. data.forEach((item: any, index: number) => {
  69. const {provinceName='',cityName='',regionName=''} = item
  70. forms.areaColumns.push({
  71. text: provinceName + ' ' + cityName + ' ' + (regionName ? regionName : ''),
  72. value: index
  73. })
  74. })
  75. // 没有缓存
  76. if (!sessionStorage.getItem('areaIdx')) {
  77. const defaultIndex = data.findIndex((item: any) => item.defaultFlag)
  78. forms.areaIdx = defaultIndex !== -1 ? Number(defaultIndex) : 0
  79. }
  80. forms.currentArea = forms.areaColumns.length ? forms.areaColumns[forms.areaIdx].text : ''
  81. forms.currentAreaInfo = forms.areaList.length ? forms.areaList[forms.areaIdx] : null;
  82. } catch (error) {
  83. }
  84. await queryInfo();
  85. await getList();
  86. }
  87. const queryInfo = async () => {
  88. try {
  89. const { provinceCode='',cityCode='',regionCode='' } = forms.currentAreaInfo
  90. const res = await request.post(
  91. '/edu-app/open/schoolMeetingQuestion/areaSummarySum',
  92. {
  93. data: {
  94. tenantId: forms.tenantId,
  95. provinceCode,
  96. cityCode,
  97. districtCode: regionCode,
  98. }
  99. }
  100. );
  101. forms.totalInfo = res.data|| {}
  102. } catch (error) {
  103. }
  104. }
  105. const getList = async () => {
  106. try {
  107. const { provinceCode='',cityCode='',regionCode='' } = forms.currentAreaInfo
  108. const res = await request.post(
  109. '/edu-app/open/schoolMeetingQuestion/areaSummary',
  110. {
  111. data: {
  112. tenantId: forms.tenantId,
  113. schoolName: forms.schoolName,
  114. provinceCode,
  115. cityCode,
  116. districtCode: regionCode,
  117. sortType: forms.sortType,
  118. sortField: forms.sortField,
  119. }
  120. }
  121. );
  122. forms.schoolList = res?.data || []
  123. } catch {
  124. //
  125. } finally {
  126. //
  127. }
  128. };
  129. const state = reactive({
  130. saveLoading: false,
  131. image: null as any,
  132. shareLoading: false
  133. });
  134. const skipDetail = (id: any) => {
  135. // sessionStorage.setItem('areaIdx', forms.areaIdx)
  136. // sessionStorage.setItem('areaTenantName', forms.totalInfo.tenantName || '')
  137. sessionStorage.setItem('yqsFilterParams', JSON.stringify({
  138. schoolName: forms.schoolName,
  139. sortType: forms.sortType,
  140. sortField: forms.sortField,
  141. }))
  142. router.push({
  143. path: '/statistics-detail',
  144. query: {
  145. id,
  146. }
  147. });
  148. }
  149. const filterList = (val: string) => {
  150. if (forms.sortField !== val) {
  151. forms.sortType = 'DESC'
  152. } else {
  153. forms.sortType = forms.sortType === 'DESC' ? 'ASC' : 'DESC'
  154. }
  155. forms.sortField = val
  156. getList()
  157. }
  158. const formatNumberWithComma = (num: number | string) => {
  159. // 将数字转换为字符串,去掉小数点后面的部分
  160. let [integer, decimal] = num.toString().split('.');
  161. // 使用正则表达式添加千分位分隔符
  162. integer = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  163. // 如果有小数部分,则保留小数部分
  164. return decimal ? `${integer}.${decimal}` : integer;
  165. }
  166. const initWxShare = () => {
  167. const shareTitle = (forms.totalInfo.tenantName||'') + '音乐(器乐)数字化转型问卷统计';
  168. const weChatShare = useWeChatShare(
  169. shareTitle,
  170. '科技赋能音乐(器乐)学习,在每一个孩子心中奏响美妙的乐章。',
  171. window.location.origin + '/classroom-app/shareImg/questionnaire-statistics.png'
  172. );
  173. if (browser().weixin) {
  174. weChatShare.getAppSignature()
  175. }
  176. }
  177. const onRefresh = async () => {
  178. console.log('刷新111')
  179. forms.areaColumns = []
  180. finished.value = false;
  181. forms.areaColumns = []
  182. // 重新加载数据
  183. // 将 loading 设置为 true,表示处于加载状态
  184. loading.value = true;
  185. await queryArea();
  186. refreshing.value = false
  187. };
  188. onMounted(async () => {
  189. console.log('刷新页面')
  190. forms.areaIdx = sessionStorage.getItem('areaIdx') || 0;
  191. // @ts-ignore
  192. const qsFilterParams: any = sessionStorage.getItem('yqsFilterParams') ? JSON.parse(sessionStorage.getItem('yqsFilterParams')) : {};
  193. forms.schoolName = qsFilterParams.schoolName || ''
  194. forms.sortField = qsFilterParams.sortField || 'totalNum'
  195. forms.sortType = qsFilterParams.sortType || 'DESC'
  196. await queryArea();
  197. initWxShare();
  198. });
  199. return () => (
  200. <OFullRefresh
  201. v-model:modelValue={refreshing.value}
  202. freshDisabled={forms.areaStatus}
  203. onRefresh={onRefresh}
  204. class={styles.refreshC}>
  205. <div class={[styles.statisBody, forms.areaColumns.length == 1 ? styles.statisBody2 : styles.statisBody1]}>
  206. {
  207. forms.areaColumns.length > 1 &&
  208. <div class={[styles.spColumn, forms.areaStatus && styles.openVal]} onClick={() => {
  209. forms.areaOptionIndex = [Number(forms.areaIdx)]
  210. forms.areaStatus = true
  211. }}>
  212. <img src={positionIcon} />
  213. <p>{forms.currentArea}</p>
  214. <i></i>
  215. </div>
  216. }
  217. <div class={styles.scContent}>
  218. <div class={styles.scBgBox}>
  219. <img class={styles.scBg1} src={tbgIcon1} />
  220. <img class={styles.scBg2} src={tbgIcon2} />
  221. <img class={styles.scBg3} src={tbgIcon3} />
  222. </div>
  223. {/* <div class={styles.scTop}>
  224. <div>参与学校</div><span>{formatNumberWithComma(forms.totalInfo.schoolNum || 0)}</span><i>所</i>
  225. </div> */}
  226. {/* <ul class={styles.scBottom}>
  227. <li>
  228. <div class={styles.sNum}><span class={styles.sRed}>{formatNumberWithComma(forms.totalInfo.totalNum || 0)}</span><i>人</i></div>
  229. <div class={styles.sDesc}>
  230. <img src={scIcon1} />
  231. 参与调查
  232. </div>
  233. </li>
  234. <li>
  235. <div class={styles.sNum}><span class={styles.sBlue}>{formatNumberWithComma(forms.totalInfo.supportNum || 0)}</span><i>人</i></div>
  236. <div class={styles.sDesc}>
  237. <img src={scIcon2} />
  238. 支持学校开展
  239. </div>
  240. </li>
  241. <li>
  242. <div class={styles.sNum}><span class={styles.sBlue}>{Number(forms.totalInfo.supportRate || 0).toFixed(2)}%</span></div>
  243. <div class={styles.sDesc}>
  244. <img src={scIcon3} />
  245. 支持率
  246. </div>
  247. </li>
  248. </ul> */}
  249. <div class={styles.scInfo}>
  250. <div class={styles.scInfoItem}>
  251. <div class={styles.scmTop}><img src={schoolIcon2} />学校登记</div>
  252. <div class={styles.scmBottom}><span class={styles.sColor1}>{formatNumberWithComma(forms.totalInfo.schoolNum || 0)}</span><i>所</i></div>
  253. </div>
  254. <div class={styles.scInfoItem}>
  255. <div class={styles.scmTop}><img src={tjnumIicon} />参与登记</div>
  256. <div class={styles.scmBottom}><span class={styles.sColor2}>{formatNumberWithComma(forms.totalInfo.totalNum || 0)}</span><i>人</i></div>
  257. </div>
  258. </div>
  259. </div>
  260. {/** 搜索栏 */}
  261. <div class={styles.searechInfo}>
  262. {/* <OSearch
  263. class={styles.allDataWrap}
  264. shape="round"
  265. background="#F6F8F9"
  266. inputBackground="white"
  267. placeholder="请输入学校名称"
  268. onSearch={val => {
  269. forms.schoolName = val;
  270. forms.page = 1;
  271. refreshing.value = true;
  272. getList();
  273. }}></OSearch> */}
  274. <img src={searchIcon} class={styles.searchIcon} />
  275. <Field
  276. clearable={true}
  277. inputAlign="left"
  278. placeholder="请输入学校名称"
  279. autocomplete="off"
  280. center
  281. maxlength={30}
  282. v-model={forms.schoolName}
  283. onUpdate:modelValue={(val: any) => {
  284. // 输入框内容变化时触发
  285. // console.log('搜索内容变化',val)
  286. forms.schoolName = val
  287. sessionStorage.setItem('yqsFilterParams', JSON.stringify({
  288. schoolName: forms.schoolName,
  289. sortType: forms.sortType,
  290. sortField: forms.sortField,
  291. }))
  292. getList()
  293. }}>
  294. </Field>
  295. <img src={searchBtn} class={styles.searchBtn} onClick={getList} />
  296. </div>
  297. {/** 排序栏 */}
  298. {/* <ul class={styles.sortColumn}>
  299. <li class={forms.sortField === 'totalNum' && styles.sortActive} onClick={() => filterList('totalNum')}>
  300. <span>参与调查人数</span>
  301. <i class={[(forms.sortField === 'totalNum' && forms.sortType === 'DESC') && styles.actDown, (forms.sortField === 'totalNum' && forms.sortType === 'ASC') && styles.actUp]}></i>
  302. </li>
  303. <li class={forms.sortField === 'supportNum' && styles.sortActive} onClick={() => filterList('supportNum')}>
  304. <span>支持人数</span>
  305. <i class={[(forms.sortField === 'supportNum' && forms.sortType === 'DESC') && styles.actDown, (forms.sortField === 'supportNum' && forms.sortType === 'ASC') && styles.actUp]}></i>
  306. </li>
  307. <li class={forms.sortField === 'supportRate' && styles.sortActive} onClick={() => filterList('supportRate')}>
  308. <span>支持率</span>
  309. <i class={[(forms.sortField === 'supportRate' && forms.sortType === 'DESC') && styles.actDown, (forms.sortField === 'supportRate' && forms.sortType === 'ASC') && styles.actUp]}></i>
  310. </li>
  311. </ul> */}
  312. {/** 学校列表 */}
  313. {
  314. forms.schoolList.length ?
  315. <div class={styles.scList}>
  316. {forms.schoolList.map((item: any) => (
  317. <div class={styles.sItem} onClick={() => skipDetail(item.schoolAreaId)}>
  318. <div class={styles.itemTile}>
  319. {/* <img src={schoolIcon} /> */}
  320. <p>{item.schoolName}</p>
  321. <i></i>
  322. </div>
  323. <div class={styles.itemTotalNum}>
  324. <span class={styles.itLeft}><img src={tjnumIicon} />参与登记</span>
  325. <span class={styles.itRight}>{formatNumberWithComma(item.totalNum)}<i>人</i></span>
  326. </div>
  327. {/* <ul class={styles.itemContent}>
  328. <li>
  329. <div class={styles.icTop}>
  330. <span class={styles.sRed}>{formatNumberWithComma(item.totalNum)}</span><i>人</i>
  331. </div>
  332. <p>参与调查</p>
  333. </li>
  334. <li>
  335. <div class={styles.icTop}>
  336. <span class={styles.sBlue}>{formatNumberWithComma(item.supportNum)}</span><i>人</i>
  337. </div>
  338. <p>支持学校开展</p>
  339. </li>
  340. <li>
  341. <div class={styles.icTop}>
  342. <span class={styles.sBlue}>{Number(item.supportRate).toFixed(2)}%</span>
  343. </div>
  344. <p>支持率</p>
  345. </li>
  346. </ul> */}
  347. </div>
  348. ))}
  349. </div> :
  350. <OEmpty description="暂无内容" class={styles.emptyC} />
  351. }
  352. {/* 区域 */}
  353. <Popup
  354. v-model:show={forms.areaStatus}
  355. position="bottom"
  356. round
  357. safeAreaInsetBottom
  358. lazyRender={false}
  359. class={'popupBottomSearch'}
  360. onOpen={() => {
  361. forms.areaPopupShow = true;
  362. }}
  363. onClosed={() => {
  364. forms.areaPopupShow = false;
  365. }}>
  366. {forms.areaPopupShow && (
  367. <Picker
  368. showToolbar
  369. v-model={forms.areaOptionIndex}
  370. columns={forms.areaColumns}
  371. onCancel={() => (forms.areaStatus = false)}
  372. onConfirm={(val: any) => {
  373. // forms.gradeAndClassIndex = [val.selectedOptions[0].value, val.selectedOptions[1].value]
  374. // forms.currentArea = val.selectedOptions[0].text;
  375. // forms.currentClass = val.selectedOptions[1].text;
  376. forms.currentArea = val.selectedOptions[0].text
  377. forms.areaOptionIndex = [val.selectedOptions[0].value]
  378. forms.areaIdx = val.selectedOptions[0].value
  379. forms.areaStatus = false;
  380. forms.schoolName = '';
  381. forms.currentAreaInfo = forms.areaList[val.selectedOptions[0].value]
  382. sessionStorage.setItem('areaIdx', forms.areaIdx)
  383. queryInfo()
  384. getList()
  385. console.log('选择1111',val,forms.areaOptionIndex)
  386. }}
  387. />
  388. )}
  389. </Popup>
  390. {/* <MWxTip /> */}
  391. </div>
  392. </OFullRefresh>
  393. );
  394. }
  395. });