index.tsx 14 KB

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