index.vue 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942
  1. <template>
  2. <view class="report-export-page">
  3. <view class="report-export-search-bar-container">
  4. <view class="report-export-search-bar">
  5. <view class="report-export-search-input-wrap">
  6. <image src="../../../static/images/search.png" mode="scaleToFill" class="report-export-search-icon" />
  7. <input class="report-export-search-input" v-model="keyword" placeholder="搜索公司" />
  8. <view class="report-export-search-btn" @click="onSearch">搜索</view>
  9. </view>
  10. <view class="report-export-filter-btn" @click="onFilter">
  11. <image src="../../../static/images/filter.png" mode="scaleToFill" class="report-export-filter-icon" />
  12. <text class="report-export-filter-text">筛选</text>
  13. </view>
  14. </view>
  15. </view>
  16. <view class="scan-rate-ranges-container">
  17. <view class="scan-rate-ranges">
  18. <view class="scan-rate-ranges-content">
  19. <view v-for="(value, i) in options.status" :key="value" class="scan-rate-range" :class="{
  20. 'scan-rate-active': filterForm.status == value,
  21. }" @click.stop="pickFilterOption('status', value)">{{ value }}</view>
  22. </view>
  23. </view>
  24. </view>
  25. <view v-if="loading" class="report-export-list-scroll" :style="{ height: 'auto' }">
  26. <view class="report-export-loading-row">
  27. <view class="report-export-loading-wrapper">
  28. <image class="report-export-loading-icon" src="../../../static/images/loading.png" />
  29. </view>
  30. </view>
  31. </view>
  32. <scroll-view v-else-if="list.length > 0" class="report-export-list-scroll" scroll-y="true"
  33. :style="{ height: listViewHeight }" @scrolltolower="onScrollToLower">
  34. <view class="report-export-item-card" v-for="(item, i) in list" :key="item.id">
  35. <view class="report-export-item-header">
  36. <text class="report-export-item-title" @click="showModal(item)">{{ getCustomerName(item) }}报表</text>
  37. <text class="report-export-status" :class="'report-export-status-' + item.status">{{
  38. getStatusText(item.status) }}</text>
  39. </view>
  40. <view class="report-export-item-row">品种:{{ item.physicName || "" }}</view>
  41. <view class="report-export-item-row">规格:{{ item.pkgSpec || "" }}</view>
  42. <view class="report-export-item-row">时间:{{ formatDate(item.beginTime) }}~{{
  43. formatDate(item.endTime)
  44. }}</view>
  45. <!-- <view
  46. class="report-export-item-row"
  47. style="color: red"
  48. v-if="item.remark !== ''"
  49. >任务失败:{{ item.remark || "" }}</view
  50. > -->
  51. <view v-if="item.status == 2" class="report-export-progress-wrap">
  52. <view class="report-export-progress">
  53. <view class="report-export-progress-fill" :style="{ width: `${item.progress || 10}%` }"></view>
  54. <text class="report-export-progress-text">{{
  55. item.progress || 10
  56. }}</text>
  57. </view>
  58. </view>
  59. <view v-if="item.status == 1" class="report-export-action-row">
  60. <view class="report-export-action-btn report-export-primary" @click="onStart(item)">
  61. 确认开始计算
  62. </view>
  63. </view>
  64. <view v-else-if="item.status == 3" class="report-export-action-row">
  65. <view class="report-export-action-btn report-export-info" @click="toDetail(item)">查看</view>
  66. <view class="report-export-action-btn report-export-primary" @click="onSend(item)">
  67. 导出
  68. </view>
  69. </view>
  70. </view>
  71. <view class="report-export-loading-row" v-if="hasmore">
  72. <view class="report-export-loading-wrapper">
  73. <image class="report-export-loading-icon" src="../../../static/images/loading.png" />
  74. </view>
  75. </view>
  76. </scroll-view>
  77. <EmptyView v-else text="暂无导出任务" />
  78. <view class="report-export-footer">
  79. <view class="report-export-footer-btn" @click="onCreate">新建任务</view>
  80. </view>
  81. <view v-show="createModalOpen || filterModalOpen || emailModalOpen" class="report-export-create-modal-mask"
  82. @click="closeCreate">
  83. </view>
  84. <view class="report-export-create-modal" :class="{ 'report-export-create-modal--open': createModalOpen }">
  85. <view class="report-export-create-modal-title" @click="closeDropdownAll">
  86. <text>{{ taskTitle }}</text>
  87. <view class="report-export-create-modal-close" @click.stop="closeCreate">×</view>
  88. </view>
  89. <view class="report-export-create-modal-body" :style="{ paddingBottom: 0 }" @click="closeDropdownAll">
  90. <scroll-view scroll-y="true" :style="{
  91. height: '750rpx',
  92. paddingBottom: '20rpx',
  93. }">
  94. <view class="report-export-create-modal-row">
  95. <text class="report-export-create-modal-label">省份</text>
  96. <view class="report-export-create-modal-inputwrap"
  97. @click.stop="modalType !== 'read' && openDropdown('region')">
  98. <view class="report-export-create-modal-static">{{
  99. form.region && form.region.regionName
  100. ? form.region.regionName
  101. : "请选择省份"
  102. }}</view>
  103. <view class="report-export-input-arrow" v-if="modalType !== 'read'"></view>
  104. <view class="report-export-create-modal-dropdown" v-if="dropdown.region" @click.stop
  105. :style="dropdownPosStyle()">
  106. <view class="report-export-dropdown-search-row">
  107. <input class="report-export-dropdown-search-input" v-model="searchForm.region"
  108. :disabled="modalType === 'read'" @input="modalType !== 'read' && onInput('region')"
  109. @focus="onSearchFocus" @blur="onSearchBlur" />
  110. </view>
  111. <scroll-view class="report-export-create-modal-dropdown-list" scroll-y>
  112. <view class="report-export-create-modal-dropdown-item" v-for="(op, i) in filteredOptions('region')"
  113. :key="'r-' + i" @click.stop="
  114. modalType !== 'read' && pickOption('region', op)
  115. ">{{ op.regionName }}
  116. </view>
  117. <view v-if="
  118. !filteredOptions('region') ||
  119. filteredOptions('region').length === 0
  120. " class="report-export-create-modal-dropdown-item">
  121. 未查找到该省份</view>
  122. </scroll-view>
  123. </view>
  124. </view>
  125. </view>
  126. <view class="report-export-create-modal-row">
  127. <text class="report-export-create-modal-label">客户类型</text>
  128. <view class="report-export-create-modal-inputwrap"
  129. @click.stop="modalType !== 'read' && openDropdown('customerType')">
  130. <view class="report-export-create-modal-static">{{
  131. form.customerType || "请选择客户类型"
  132. }}</view>
  133. <view class="report-export-input-arrow" v-if="modalType !== 'read'"></view>
  134. <view class="report-export-create-modal-dropdown" v-if="dropdown.customerType" @click.stop
  135. :style="dropdownPosStyle()">
  136. <view class="report-export-create-modal-dropdown-item"
  137. v-for="(op, i) in filteredOptions('customerType')" :key="'t-' + i" @click.stop="
  138. modalType !== 'read' && pickOption('customerType', op)
  139. ">{{ op }}</view>
  140. <view v-if="filteredOptions('customerType').length === 0"
  141. class="report-export-create-modal-dropdown-item">未查找到该客户类型</view>
  142. </view>
  143. </view>
  144. </view>
  145. <view class="report-export-create-modal-row">
  146. <text class="report-export-create-modal-label">客户</text>
  147. <view class="report-export-create-modal-inputwrap"
  148. @click.stop="modalType !== 'read' && openDropdown('customer')">
  149. <view class="report-export-create-modal-static" :style="{ maxHeight: 'auto', overflowY: 'visible' }">
  150. <block v-if="Array.isArray(form.customer) && form.customer.length">
  151. <view :style="{
  152. maxHeight: '100rpx',
  153. overflowY: 'auto',
  154. paddingRight: '40rpx',
  155. }">
  156. <text v-for="(op, i) in form.customer" :key="'cust-tag-' + i" class="customer-chip">
  157. {{ op.customerName }}
  158. <text class="customer-chip-close" @click.stop="
  159. modalType !== 'read' &&
  160. removeCustomer(op.customerName)
  161. ">×</text>
  162. </text>
  163. </view>
  164. </block>
  165. <text v-else>请选择客户</text>
  166. <text v-if="
  167. form.customer &&
  168. form.customer.length &&
  169. modalType !== 'read'
  170. " class="customer-clear-all" @click.stop="modalType !== 'read' && clearAllCustomers()">×</text>
  171. </view>
  172. <view class="report-export-input-arrow" v-if="modalType !== 'read'"></view>
  173. <view class="report-export-create-modal-dropdown" v-if="dropdown.customer" @click.stop :style="[
  174. dropdownPosStyle(),
  175. { maxHeight: 'none', overflow: 'visible' },
  176. ]">
  177. <view class="report-export-dropdown-search-row">
  178. <input class="report-export-dropdown-search-input" v-model="customerSearch"
  179. :disabled="modalType === 'read'" @input="modalType !== 'read' && onInput('customer')"
  180. @focus="onSearchFocus" @blur="onSearchBlur" />
  181. </view>
  182. <scroll-view class="report-export-create-modal-dropdown-list" scroll-y lower-threshold="20"
  183. @scrolltolower="getCustomerOptions">
  184. <view class="report-export-create-modal-dropdown-item" :class="{
  185. 'report-export-selected': isCustomerSelected(
  186. op.customerName,
  187. ),
  188. }" v-for="(op, i) in customers" :key="'cust-' + i" @click.stop="
  189. modalType !== 'read' && pickOption('customer', op)
  190. ">{{ op.customerName }}</view>
  191. <view v-if="customers.length === 0 && !customerHasMore"
  192. class="report-export-create-modal-dropdown-item">未查找到该客户</view>
  193. <view v-if="customerHasMore" class="report-export-loading-row">
  194. <view class="report-export-loading-wrapper">
  195. <image class="report-export-loading-icon" src="../../../static/images/loading.png" />
  196. </view>
  197. </view>
  198. </scroll-view>
  199. </view>
  200. </view>
  201. </view>
  202. <view class="report-export-create-modal-row">
  203. <text class="report-export-create-modal-label">其它客户</text>
  204. <view class="report-export-create-modal-inputwrap">
  205. <input class="report-export-dropdown-search-input" v-model="form.otherCustomer"
  206. placeholder="请填写(多个客户用半角逗号隔开)" placeholder-class="report-export-dropdown-other-customer-input"
  207. :disabled="modalType === 'read'" :style="{ color: '#666', padding: 0, border: 'none' }" />
  208. </view>
  209. </view>
  210. <view class="report-export-create-modal-row">
  211. <text class="report-export-create-modal-label">其它客户信用代码</text>
  212. <view class="report-export-create-modal-inputwrap">
  213. <input class="report-export-dropdown-search-input" v-model="form.otherCustomerCode"
  214. placeholder="请填写信用代码(依照其他客户填写顺序用半角逗号隔开)" placeholder-class="report-export-dropdown-other-customer-input"
  215. :disabled="modalType === 'read'" :style="{ color: '#666', padding: 0, border: 'none' }" />
  216. </view>
  217. </view>
  218. <view class="report-export-create-modal-row">
  219. <text class="report-export-create-modal-label">品种</text>
  220. <view class="report-export-create-modal-inputwrap"
  221. @click.stop="modalType !== 'read' && openDropdown('product')">
  222. <view class="report-export-create-modal-static">{{
  223. form.product?.physicName || "请选择品种"
  224. }}</view>
  225. <view class="report-export-input-arrow" v-if="modalType !== 'read'"></view>
  226. <view class="report-export-create-modal-dropdown" :style="[{ top: 'auto', bottom: '84rpx' }]"
  227. v-if="dropdown.product" @click.stop>
  228. <view class="report-export-dropdown-search-row">
  229. <input class="report-export-dropdown-search-input" v-model="searchForm.product"
  230. :disabled="modalType === 'read'" @input="modalType !== 'read' && onInput('product')"
  231. @focus="onSearchFocus" @blur="onSearchBlur" />
  232. </view>
  233. <scroll-view class="report-export-create-modal-dropdown-list" scroll-y
  234. @scrolltolower="loadMoreProducts('create')">
  235. <view class="report-export-create-modal-dropdown-item" v-for="(op, i) in displayProducts"
  236. :key="'p-' + i" @click.stop="
  237. modalType !== 'read' && pickOption('product', op)
  238. ">{{ op.physicName }}
  239. </view>
  240. <view v-if="displayProducts?.length === 0" class="report-export-create-modal-dropdown-item">
  241. 未查找到该品种</view>
  242. </scroll-view>
  243. </view>
  244. </view>
  245. </view>
  246. <view class="report-export-create-modal-row">
  247. <text class="report-export-create-modal-label">规格</text>
  248. <view class="report-export-create-modal-inputwrap" :class="{
  249. 'report-export-input-disabled':
  250. !form.product?.drugEntBaseInfoId,
  251. }" @click.stop="
  252. modalType !== 'read' &&
  253. form.product?.drugEntBaseInfoId &&
  254. openDropdown('pkgSpec')
  255. ">
  256. <view class="report-export-create-modal-static">{{
  257. form.pkgSpec || "请选择规格(请先选择品种)"
  258. }}</view>
  259. <view class="report-export-input-arrow" v-if="modalType !== 'read'"></view>
  260. <view class="report-export-create-modal-dropdown" v-if="dropdown.pkgSpec" @click.stop
  261. :style="[{ top: 'auto', bottom: '84rpx' }]">
  262. <view class="report-export-create-modal-dropdown-item" v-for="(op, i) in filteredOptions('pkgSpec')"
  263. :key="'t-' + i" @click.stop="
  264. modalType !== 'read' && pickOption('pkgSpec', op)
  265. ">{{ op }}</view>
  266. <view v-if="filteredOptions('pkgSpec')?.length === 0" class="report-export-create-modal-dropdown-item">
  267. 未查找到该品种规格</view>
  268. </view>
  269. </view>
  270. </view>
  271. <view class="report-export-create-modal-row">
  272. <text class="report-export-create-modal-label">时间</text>
  273. <view class="report-export-create-modal-inputwrap" @click="openDatePicker">
  274. <view class="report-export-create-modal-static report-export-input-simulator" :style="{
  275. color: dateRange && dateRange.length ? '#333' : '#606266',
  276. }">
  277. <uni-icons type="calendar" size="22" color="#c0c4cc"></uni-icons>
  278. <view style="flex: 1; text-align: center">{{
  279. dateRange && dateRange.length ? dateRange[0] : "开始时间"
  280. }}
  281. </view>
  282. <view>-</view>
  283. <view style="flex: 1; text-align: center">{{
  284. dateRange && dateRange.length ? dateRange[1] : "结束时间"
  285. }}
  286. </view>
  287. </view>
  288. <view class="report-export-input-simulator-clear" v-if="dateRange && dateRange.length"
  289. @click.stop="dateRange = []">
  290. <uni-icons type="clear" size="22" color="#c0c4cc"></uni-icons>
  291. </view>
  292. </view>
  293. </view>
  294. </scroll-view>
  295. <!-- Hidden Picker for API access -->
  296. <view style="position: absolute; left: -10000px; top: 0">
  297. <uni-datetime-picker ref="datePicker" type="daterange" v-model="dateRange" @change="onDateChange" />
  298. </view>
  299. </view>
  300. <view class="report-export-create-modal-footer" @click="closeDropdownAll">
  301. <view class="report-export-create-modal-btn" @click.stop="confirmCreate" v-if="modalType !== 'read'">{{
  302. modalType === "create" ? "新建任务" : "修改任务" }}</view>
  303. <view :style="{ display: 'flex', 'justify-content': 'space-between' }" v-else>
  304. <view class="report-export-create-modal-btn" :style="currentItem.status !== '2'
  305. ? { flex: '0 0 40%' }
  306. : { flex: '0 0 100%' }
  307. " @click.stop="closeCreate">关闭</view>
  308. <view class="report-export-create-modal-btn" :style="{ background: 'red', flex: '0 0 40%' }"
  309. @click.stop="confirmDelete" v-if="currentItem.status !== '2'">删除</view>
  310. </view>
  311. </view>
  312. </view>
  313. <view class="report-export-create-modal" :class="{ 'report-export-create-modal--open': filterModalOpen }">
  314. <view class="report-export-create-modal-title" @click="closeDropdownAll">筛选条件</view>
  315. <view class="report-export-create-modal-body" @click="closeDropdownAll">
  316. <view class="report-export-create-modal-row">
  317. <text class="report-export-create-modal-label">品种:</text>
  318. <view class="report-export-create-modal-inputwrap" @click.stop="openFilterDropdown('product')">
  319. <view class="report-export-create-modal-static">{{
  320. filterForm.product?.physicName || "请选择品种"
  321. }}</view>
  322. <view class="report-export-create-modal-dropdown" :style="[{ top: 'auto', bottom: '84rpx' }]"
  323. v-if="filterDropdown.product" @click.stop>
  324. <view class="report-export-dropdown-search-row">
  325. <input class="report-export-dropdown-search-input" v-model="filterSearchForm.product"
  326. @input="onFilterInput('product')" @focus="onSearchFocus" @blur="onSearchBlur" />
  327. </view>
  328. <scroll-view class="report-export-create-modal-dropdown-list" scroll-y
  329. @scrolltolower="loadMoreProducts('filter')">
  330. <view class="report-export-create-modal-dropdown-item" v-for="(op, i) in filterDisplayProducts"
  331. :key="'prd-' + i" @click.stop="pickFilterOption('product', op)">{{ op.physicName }}</view>
  332. <view v-if="filterDisplayProducts?.length === 0" class="report-export-create-modal-dropdown-item">
  333. 未查找到该品种
  334. </view>
  335. </scroll-view>
  336. </view>
  337. </view>
  338. </view>
  339. <!-- <view class="report-export-create-modal-row">
  340. <text class="report-export-create-modal-label">规格</text>
  341. <view class="report-export-create-modal-inputwrap"
  342. :class="{ 'report-export-input-disabled': !filterForm.product?.drugEntBaseInfoId }"
  343. @click.stop="filterForm.product?.drugEntBaseInfoId && openFilterDropdown('pkgSpec')">
  344. <view class="report-export-create-modal-static">{{
  345. filterForm.pkgSpec || "请选择品种规格(请先选择品种)"
  346. }}</view>
  347. <view class="report-export-input-arrow"></view>
  348. <view class="report-export-create-modal-dropdown" v-if="filterDropdown.pkgSpec" @click.stop
  349. :style="[{ top: 'auto', bottom: '84rpx' }]">
  350. <view class="report-export-create-modal-dropdown-item" v-for="(op, i) in filteredOptions('pkgSpec')"
  351. :key="'t-' + i" @click.stop="
  352. pickFilterOption('pkgSpec', op)
  353. ">{{ op }}</view>
  354. <view v-if="filteredOptions('pkgSpec')?.length === 0" class="report-export-create-modal-dropdown-item">
  355. 未查找到该品种规格</view>
  356. </view>
  357. </view>
  358. </view> -->
  359. <view class="report-export-create-modal-row">
  360. <text class="report-export-create-modal-label">时间:</text>
  361. <view class="report-export-create-modal-inputwrap" v-if="filterModalOpen">
  362. <uni-datetime-picker type="daterange" :border="false" v-model="filterDateRange"
  363. @change="onFilterDateChange" />
  364. </view>
  365. </view>
  366. </view>
  367. <view class="report-export-create-modal-footer" @click="closeDropdownAll"
  368. :style="{ display: 'flex', justifyContent: 'space-between' }">
  369. <view class="report-export-create-modal-btn" :style="{
  370. background: '#fff',
  371. color: '#666',
  372. border: '1rpx solid #dcdfe6',
  373. flex: '0 0 45%',
  374. }" @click.stop="resetFilter">重置</view>
  375. <view class="report-export-create-modal-btn" :style="{ flex: '0 0 45%' }" @click.stop="confirmFilter">确认</view>
  376. </view>
  377. </view>
  378. <view class="report-export-create-modal report-export-create-email-modal"
  379. :class="{ 'report-export-create-modal--open': emailModalOpen }" v-if="emailModalOpen">
  380. <view class="report-export-create-modal-title">
  381. <text>发送至邮箱</text>
  382. <view class="report-export-create-modal-close" @click.stop="closeEmailModal">×</view>
  383. </view>
  384. <view class="report-export-create-modal-body" :style="{ padding: '40rpx' }">
  385. <!-- <view class="report-export-email-input-wrap" :class="{ 'report-export-input-error': emailError }">
  386. <input class="report-export-email-input" v-model="emailForm.email" placeholder="请填写邮箱"
  387. placeholder-style="color: #c0c4cc" @input="emailError = false" />
  388. <text class="report-export-email-suffix">@999.com.cn</text>
  389. </view> -->
  390. <up-input v-model="emailForm.email" border="none" :customStyle="{
  391. backgroundColor: '#ebf3fb',
  392. height: '80rpx',
  393. paddingLeft: '20rpx',
  394. }" placeholder="请填写邮箱" disabled>
  395. <template #suffix style="margin-right: 30rpx"> @999.com.cn </template>
  396. </up-input>
  397. <text v-if="emailError" class="report-export-error-text">请输入邮箱</text>
  398. </view>
  399. <view class="report-export-create-modal-footer" :style="{
  400. padding: '20rpx 40rpx 40rpx',
  401. display: 'flex',
  402. 'justify-content': 'space-between',
  403. }">
  404. <view class="report-export-create-modal-btn" :style="{
  405. background: '#fff',
  406. color: '#666',
  407. border: '1rpx solid #dcdfe6',
  408. flex: '0 0 45%',
  409. }" @click.stop="closeEmailModal">取消</view>
  410. <view class="report-export-create-modal-btn" :style="{ flex: '0 0 45%' }" @click.stop="handleSendEmail">发送
  411. </view>
  412. </view>
  413. </view>
  414. </view>
  415. </template>
  416. <script>
  417. import EmptyView from "../../../wigets/empty.vue";
  418. import { formatDate, getPaginatedList } from "../../../utils/utils.js";
  419. import request from "../../../request/index.js";
  420. const customerTypeMap = {
  421. VIP客户: "VIP",
  422. 二级客户: "二级",
  423. 三级客户: "三级",
  424. };
  425. const customerTypeReverseMap = {
  426. VIP: "VIP客户",
  427. 二级: "二级客户",
  428. 三级: "三级客户",
  429. };
  430. const statusMap = {
  431. 全部: 0,
  432. 待开始: 1,
  433. 进行中: 2,
  434. 已完成: 3,
  435. };
  436. export default {
  437. components: {
  438. EmptyView,
  439. },
  440. data() {
  441. return {
  442. keyword: "",
  443. totalCount: 0,
  444. loading: true,
  445. hasmore: true,
  446. fetchLoading: false,
  447. pageNum: 1,
  448. pageSize: 10,
  449. list: [],
  450. listViewHeight: "400px",
  451. createModalOpen: false,
  452. form: {
  453. region: { regionName: "" },
  454. customerType: "",
  455. customer: [],
  456. product: { physicName: "" },
  457. otherCustomer: "",
  458. otherCustomerCode: "",
  459. },
  460. dateRange: [],
  461. computeTimer: null,
  462. dropdown: {
  463. region: false,
  464. customerType: false,
  465. customer: false,
  466. product: false,
  467. pkgSpec: false,
  468. },
  469. options: {
  470. region: [],
  471. customerType: ["VIP客户", "二级客户", "三级客户"],
  472. product: [],
  473. pkgSpec: [],
  474. status: ["全部", "已完成", "待开始", "进行中"],
  475. },
  476. // dropdown search inputs (create modal)
  477. searchForm: {
  478. region: "",
  479. product: "",
  480. },
  481. // Pagination state for products
  482. productPage: 0,
  483. productPageSize: 10,
  484. displayProducts: [], // Currently displayed products
  485. // dropdown search inputs (filter modal)
  486. filterSearchForm: {
  487. product: "",
  488. },
  489. // Pagination state for filter products
  490. filterProductPage: 0,
  491. filterDisplayProducts: [],
  492. customers: [],
  493. customerPage: 1,
  494. customerPageSize: 10,
  495. customerTotal: null,
  496. customerHasMore: true,
  497. customerLoading: false,
  498. customerDebounceTimer: null,
  499. taskTitle: "创建任务",
  500. filterModalOpen: false,
  501. filterForm: {
  502. product: { physicName: "" },
  503. status: "全部",
  504. pkgSpec: "",
  505. },
  506. filterDropdown: { product: false, pkgSpec: false },
  507. filterDateRange: [],
  508. modalType: "",
  509. dropdownUpward: false,
  510. customerSearch: "",
  511. currentItem: {},
  512. emailModalOpen: false,
  513. emailForm: {
  514. email: "",
  515. },
  516. emailError: false,
  517. };
  518. },
  519. created() {
  520. const userInfo = uni.getStorageSync("userInfo");
  521. // const staffEmail = userInfo?.ldap || "";
  522. // this.emailForm.email = staffEmail.split("@")[0];
  523. const userEmail = uni.getStorageSync('traceCode_useremail')
  524. this.emailForm.email = userEmail
  525. console.log("reportExport\index.vue,storage,userInfo", userInfo);
  526. this.initList();
  527. this.getProviceList();
  528. this.getDrugInfoName();
  529. this.fetchList();
  530. try {
  531. uni.onKeyboardHeightChange(({ height }) => {
  532. this.dropdownUpward = height > 0;
  533. });
  534. } catch (e) { }
  535. },
  536. computed: {
  537. taskTitle() {
  538. if (this.modalType === "create") {
  539. return "创建任务";
  540. } else if (this.modalType == "edit") {
  541. return "修改任务";
  542. } else if (this.modalType == "read") {
  543. return "查看任务";
  544. }
  545. },
  546. },
  547. watch: {
  548. "form.customerType"(val) {
  549. this.customerPage = 1;
  550. this.customerTotal = null;
  551. this.customerHasMore = true;
  552. this.customers = [];
  553. if (this.customerDebounceTimer) clearTimeout(this.customerDebounceTimer);
  554. this.getCustomerOptions();
  555. },
  556. "form.region": {
  557. handler() {
  558. this.customerPage = 1;
  559. this.customerTotal = null;
  560. this.customerHasMore = true;
  561. this.customers = [];
  562. if (this.customerDebounceTimer)
  563. clearTimeout(this.customerDebounceTimer);
  564. this.getCustomerOptions();
  565. },
  566. deep: true,
  567. },
  568. "emailForm.email": {
  569. handler(newVal, oldVal) {
  570. if (!oldVal && !newVal && newVal !== oldVal) {
  571. this.emailError = false;
  572. } else {
  573. this.emailError = !newVal;
  574. }
  575. },
  576. deep: true,
  577. },
  578. "filterForm.status"(val) {
  579. this.resetFetch();
  580. },
  581. },
  582. methods: {
  583. getCustomerName(data = {}) {
  584. const { customerName = "", otherCustomer = "" } = data;
  585. let name = customerName || "";
  586. if (otherCustomer) {
  587. if (name) {
  588. name += `,${otherCustomer}`;
  589. } else {
  590. name = otherCustomer;
  591. }
  592. }
  593. const arr = name?.split(",");
  594. if (arr.length == 0) return "--";
  595. return arr.length == 1
  596. ? arr[0].trim()
  597. : `${arr[0].trim()}等${arr.length - 1}家公司`;
  598. },
  599. formatDate(date) {
  600. return formatDate({ date }, "YYYY-MM-DD");
  601. },
  602. normalizeDateToYMD(value) {
  603. if (!value) return "";
  604. if (typeof value === "string") {
  605. const trimmed = value.trim();
  606. if (trimmed.length >= 10) return trimmed.slice(0, 10);
  607. return trimmed;
  608. }
  609. return this.formatDate(value);
  610. },
  611. getStatusText(status) {
  612. if (status == "1") {
  613. return "导出待开始";
  614. } else if (status == "2") {
  615. return "导出进行中";
  616. } else if (status == "3" || status == "4") {
  617. return "导出已完成";
  618. }
  619. return "未知状态";
  620. },
  621. getDrugInfoName() {
  622. request("/bills/getDrugInfoName", {
  623. path: "/reportExport/index.vue",
  624. }).then((res) => {
  625. if (res.code == 200) {
  626. const _data = res.data;
  627. this.options.product = _data;
  628. }
  629. });
  630. },
  631. getGuigeList(physicName) {
  632. if (!physicName) return;
  633. request("/report/getDrugSpec", {
  634. physicName,
  635. path: "/reportExport/index.vue",
  636. }).then((res) => {
  637. if (res.code == 200) {
  638. this.options.pkgSpec = res.data || [];
  639. }
  640. });
  641. },
  642. getProviceList() {
  643. request("/common/getProviceList", {
  644. path: "/reportExport/index.vue",
  645. }).then((res) => {
  646. if (res.code == 200) {
  647. const _data = res.data;
  648. this.options.region = _data;
  649. }
  650. });
  651. },
  652. getCustomerOptions() {
  653. if (!this.customerHasMore || this.customerLoading) return;
  654. this.customerLoading = true;
  655. request("/customer/info/getCustomerInfo", {
  656. pageNum: this.customerPage,
  657. pageSize: this.customerPageSize,
  658. customerName: this.customerSearch || "",
  659. customerLevel: customerTypeMap?.[this.form.customerType] || undefined,
  660. provinceCode: this.form?.region?.regionCode || undefined,
  661. path: "/reportExport/index.vue",
  662. }).then((res) => {
  663. if (res.code == 200) {
  664. const _data = res.data || {};
  665. this.customerTotal = _data.total || 0;
  666. const list = Array.isArray(_data.list) ? _data.list : [];
  667. this.customers = [...this.customers, ...list];
  668. if (this.customers.length >= this.customerTotal) {
  669. this.customerHasMore = false;
  670. } else {
  671. this.customerPage++;
  672. this.customerHasMore = true;
  673. }
  674. }
  675. this.customerLoading = false;
  676. });
  677. },
  678. initList() {
  679. const info = uni.getSystemInfoSync();
  680. const h = info.windowHeight || 800;
  681. this.listViewHeight = Math.max(0, h - 280) + "px";
  682. // this.list = this.genItems(Math.min(10, this.totalCount));
  683. // this.animateAll();
  684. },
  685. onFilter() {
  686. this.filterModalOpen = true;
  687. },
  688. showModal(item = {}) {
  689. const map = {
  690. 1: "edit",
  691. 2: "read",
  692. 3: "read",
  693. };
  694. this.modalType = map[item?.status] || "create";
  695. if (this.modalType === "create") {
  696. this.taskTitle = "创建任务";
  697. } else {
  698. if (this.modalType == "edit") {
  699. this.taskTitle = "修改任务";
  700. } else if (this.modalType == "read") {
  701. this.taskTitle = "查看任务";
  702. }
  703. const cNames = item.customerName ? item.customerName.split(",") : [];
  704. const cCodes = item.customerId
  705. ? String(item.customerId).split(",")
  706. : [];
  707. const regionCode = item.regionCode || item.provinceCode || "";
  708. let regionName = item.regionName || item.provinceName || "";
  709. if (!regionName && regionCode && Array.isArray(this.options.region)) {
  710. const regionItem = this.options.region.find(
  711. (r) => r.regionCode === regionCode || r.provinceCode === regionCode,
  712. );
  713. if (regionItem) {
  714. regionName = regionItem.regionName || regionItem.name || "";
  715. }
  716. }
  717. let customerTypeLabel = "";
  718. const cType = item.customerType;
  719. if (cType === 1 || cType === "1") {
  720. customerTypeLabel = "VIP客户";
  721. } else if (cType === 2 || cType === "2") {
  722. customerTypeLabel = "二级客户";
  723. } else if (cType === 3 || cType === "3") {
  724. customerTypeLabel = "三级客户";
  725. } else if (typeof cType === "string" && cType) {
  726. customerTypeLabel = customerTypeReverseMap[cType] || cType;
  727. }
  728. this.form = {
  729. customer: cCodes.map((i, index) => ({
  730. customerName: cNames[index],
  731. customerCode: i,
  732. })),
  733. region: {
  734. regionCode,
  735. regionName,
  736. },
  737. customerType: customerTypeLabel,
  738. product: {
  739. physicName: item.physicName,
  740. drugEntBaseInfoId: item.drugEntBaseInfoId,
  741. },
  742. pkgSpec: item?.pkgSpec || "",
  743. otherCustomer: item?.otherCustomer || "",
  744. otherCustomerCode: item?.otherCustomerCode || "",
  745. };
  746. if (item.physicName) {
  747. this.getGuigeList(item.physicName);
  748. }
  749. this.dateRange = [
  750. this.normalizeDateToYMD(item.beginTime),
  751. this.normalizeDateToYMD(item.endTime),
  752. ];
  753. }
  754. this.createModalOpen = true;
  755. this.currentItem = item;
  756. },
  757. fetchList() {
  758. // this.list = [];
  759. // setTimeout(() => {
  760. // const n = Math.min(10, this.totalCount || 10);
  761. // this.list = this.genItems(n);
  762. // if (!this.totalCount) this.totalCount = this.list.length;
  763. // this.animateAll();
  764. // this.fetchLoading = false;
  765. // }, 1000);
  766. if (!this.hasmore) {
  767. setTimeout(() => {
  768. this.fetchLoading = false;
  769. this.loading = false;
  770. }, 500);
  771. return;
  772. }
  773. if (this.fetchLoading) return;
  774. this.fetchLoading = true;
  775. request("/report/getReportTaskPage", {
  776. reportType: 2,
  777. taskType: statusMap?.[this.filterForm?.status] || "",
  778. drugEntBaseInfoId: this.filterForm?.product?.drugEntBaseInfoId,
  779. pkgSpec: this.filterForm?.pkgSpec || "",
  780. beginTime: this.filterDateRange[0],
  781. endTime: this.filterDateRange[1],
  782. customerName: this.keyword || "",
  783. pageNum: this.pageNum,
  784. pageSize: this.pageSize,
  785. path: "reportExport/index.vue",
  786. }).then((res) => {
  787. if (res.code == 200) {
  788. const _data = res.data || {};
  789. const { list, total } = _data;
  790. this.totalCount = total || 0;
  791. const incoming = Array.isArray(list) ? list : [];
  792. const existingIds = new Set(this.list.map((v) => v?.id));
  793. const merged = incoming.filter((v) => {
  794. const id = v?.id;
  795. return id === undefined ? true : !existingIds.has(id);
  796. });
  797. if (merged.length === 0 && incoming.length > 0) {
  798. this.hasmore = false;
  799. } else {
  800. this.list = [...this.list, ...merged];
  801. }
  802. if (this.list.length < this.totalCount) {
  803. this.hasmore = true;
  804. this.pageNum++;
  805. } else {
  806. this.hasmore = false;
  807. }
  808. // this.list.push({
  809. // ...this.list[1],
  810. // status: 3,
  811. // });
  812. // this.list.push({
  813. // ...this.list[0],
  814. // finishTime: "2025-12-15",
  815. // status: 3,
  816. // });
  817. // this.animateAll();
  818. }
  819. this.fetchLoading = false;
  820. this.loading = false;
  821. });
  822. },
  823. resetFetch() {
  824. this.loading = true;
  825. this.list = [];
  826. this.pageNum = 1;
  827. this.hasmore = true;
  828. this.fetchList();
  829. },
  830. toDetail(item) {
  831. uni.navigateTo({
  832. url: `/traceCodePackages/traceabilityReport/pages/reportExport/detail/index?id=${item.id
  833. }&title=${encodeURIComponent(this.getCustomerName(item))}`,
  834. });
  835. },
  836. onSearch() {
  837. this.resetFetch();
  838. },
  839. onCreate() {
  840. this.modalType = "create";
  841. this.taskTitle = "创建任务";
  842. this.createModalOpen = true;
  843. },
  844. closeCreate() {
  845. this.filterModalOpen = false;
  846. this.createModalOpen = false;
  847. this.closeDropdownAll();
  848. this.form = {
  849. region: { regionName: "" },
  850. customerType: "",
  851. customer: [],
  852. product: { physicName: "" },
  853. otherCustomer: "",
  854. otherCustomerCode: "",
  855. };
  856. this.searchForm = {
  857. region: "",
  858. product: "",
  859. };
  860. this.dateRange = [];
  861. if (this.computeTimer) {
  862. clearTimeout(this.computeTimer);
  863. this.computeTimer = null;
  864. }
  865. },
  866. confirmCreate() {
  867. let flag = false;
  868. Object.values(this.dropdown).forEach((v) => {
  869. if (v) {
  870. flag = true;
  871. }
  872. });
  873. if (flag) {
  874. this.closeDropdownAll();
  875. return;
  876. }
  877. if (!this.isFormComplete()) {
  878. // uni.showToast({ title: "请完整填写任务内容", icon: "none" });
  879. return;
  880. }
  881. // uni.showToast({ title: "已创建", icon: "none" });
  882. uni.showLoading({
  883. title: this.modalType === "create" ? "创建中..." : "修改中...",
  884. });
  885. const url =
  886. this.modalType === "create" ? `/report/save` : `/report/update`;
  887. const customerId = (this.form?.customer || [])
  888. .map((v) => v?.customerCode || "")
  889. .join(",");
  890. const customerName = (this.form?.customer || [])
  891. .map((v) => v?.customerName || "")
  892. .join(",");
  893. request(url, {
  894. id:
  895. this.modalType === "create" ? undefined : this.currentItem?.id || "",
  896. reportType: 2,
  897. regionCode: this.form?.region?.regionCode || "",
  898. customerType: customerTypeMap?.[this.form?.customerType] || "",
  899. customerId,
  900. customerName,
  901. otherCustomer: this.form?.otherCustomer || "",
  902. otherCustomerCode: this.form?.otherCustomerCode || "",
  903. drugEntBaseInfoId: this.form?.product?.drugEntBaseInfoId || "",
  904. pkgSpec: this.form?.pkgSpec || "",
  905. physicName: this.form?.product?.physicName || "",
  906. beginTime: this.formatDate(this.dateRange[0], "YYYY-MM-DD"),
  907. endTime: this.formatDate(this.dateRange[1], "YYYY-MM-DD"),
  908. path: "",
  909. }).then((res) => {
  910. if (res.code == 200) {
  911. uni.hideLoading();
  912. uni.showToast({
  913. title: this.modalType === "create" ? "已创建" : "已修改",
  914. icon: "none",
  915. });
  916. this.resetFetch();
  917. this.closeCreate();
  918. }
  919. });
  920. },
  921. isFormComplete() {
  922. const f = this.form;
  923. const drOk =
  924. Array.isArray(this.dateRange) &&
  925. this.dateRange.length === 2 &&
  926. this.dateRange[0] &&
  927. this.dateRange[1];
  928. let customerOk = Array.isArray(f.customer)
  929. ? f.customer.length > 0
  930. : !!f.customer;
  931. customerOk = customerOk || f.otherCustomer;
  932. if (!customerOk) {
  933. uni.showToast({ title: "请选择至少一个客户或其他客户", icon: "none" });
  934. return false;
  935. }
  936. if (!f.product?.physicName) {
  937. uni.showToast({ title: "请选择品种", icon: "none" });
  938. return false;
  939. }
  940. if (!drOk) {
  941. uni.showToast({ title: "请选择时间范围", icon: "none" });
  942. return false;
  943. }
  944. return true;
  945. // return (
  946. // f.region?.regionName &&
  947. // f.customerType &&
  948. // customerOk &&
  949. // f.product?.physicName &&
  950. // drOk
  951. // );
  952. },
  953. confirmDelete() {
  954. uni.showModal({
  955. title: "确认删除吗?",
  956. success: (res) => {
  957. if (res.confirm) {
  958. uni.showLoading();
  959. request("/report/delete", {
  960. id: this.currentItem?.id || "",
  961. path: "reportExport/index.vue",
  962. }).then((res) => {
  963. uni.hideLoading();
  964. if (res.code == 200) {
  965. uni.showToast({
  966. title: "删除成功",
  967. icon: "none",
  968. duration: 2000,
  969. });
  970. this.resetFetch();
  971. this.closeCreate();
  972. } else {
  973. uni.showToast({
  974. title: res?.msg || "删除失败",
  975. icon: "none",
  976. duration: 2000,
  977. });
  978. }
  979. });
  980. }
  981. },
  982. });
  983. },
  984. onInput(k) {
  985. this.closeDropdownAll();
  986. this.dropdown[k] = true;
  987. if (k === "customer") {
  988. this.customerPage = 1;
  989. this.customerTotal = null;
  990. this.customerHasMore = true;
  991. this.customers = [];
  992. if (this.customerDebounceTimer)
  993. clearTimeout(this.customerDebounceTimer);
  994. this.customerDebounceTimer = setTimeout(() => {
  995. this.getCustomerOptions();
  996. }, 500);
  997. return;
  998. }
  999. if (k === "product") {
  1000. this.initProductList("create");
  1001. }
  1002. },
  1003. closeDropdownAll() {
  1004. this.dropdown = {
  1005. region: false,
  1006. customerType: false,
  1007. customer: false,
  1008. product: false,
  1009. pkgSpec: false,
  1010. };
  1011. this.filterDropdown.product = false;
  1012. this.filterDropdown.pkgSpec = false;
  1013. },
  1014. openFilterDropdown(k) {
  1015. this.closeDropdownAll();
  1016. this.filterDropdown[k] = true;
  1017. if (k === "product") {
  1018. this.initProductList("filter");
  1019. }
  1020. },
  1021. toggleFilterDropdown(k) {
  1022. this.filterDropdown[k] = !this.filterDropdown[k];
  1023. },
  1024. onFilterInput(k) {
  1025. this.closeDropdownAll();
  1026. this.filterDropdown[k] = true;
  1027. if (k === "product") {
  1028. this.initProductList("filter");
  1029. }
  1030. },
  1031. pickFilterOption(k, v) {
  1032. if (!["status"].includes(k) && this.filterForm[k] === v) {
  1033. this.filterForm[k] = "";
  1034. this.filterDropdown[k] = false;
  1035. return;
  1036. }
  1037. this.filterForm[k] = v;
  1038. if (k === "product") {
  1039. this.filterForm.pkgSpec = "";
  1040. this.getGuigeList(v.physicName);
  1041. }
  1042. this.filterDropdown[k] = false;
  1043. },
  1044. filteredFilterOptions(k) {
  1045. const arr = k === "product" ? this.products || [] : [];
  1046. const q = String(this.filterForm[k] || "").trim();
  1047. if (!q) return arr;
  1048. return arr.filter((it) => it.indexOf(q) !== -1);
  1049. },
  1050. onFilterDateChange() { },
  1051. confirmFilter() {
  1052. this.filterModalOpen = false;
  1053. this.resetFetch();
  1054. },
  1055. resetFilter() {
  1056. this.filterForm = {
  1057. product: { physicName: "" },
  1058. status: "全部",
  1059. pkgSpec: "",
  1060. };
  1061. this.filterSearchForm.product = "";
  1062. this.filterProductPage = 0;
  1063. this.filterDisplayProducts = [];
  1064. this.filterDropdown = { product: false, pkgSpec: false };
  1065. this.filterDateRange = [];
  1066. this.resetFetch();
  1067. },
  1068. openDropdown(k) {
  1069. this.closeDropdownAll();
  1070. this.dropdown[k] = true;
  1071. if (k === "customer") {
  1072. if (!this.customers || this.customers.length === 0) {
  1073. this.customerPage = 1;
  1074. this.customerTotal = null;
  1075. this.customerHasMore = true;
  1076. this.getCustomerOptions();
  1077. }
  1078. }
  1079. if (k === "product") {
  1080. this.initProductList("create");
  1081. }
  1082. },
  1083. toggleDropdown(k) {
  1084. this.dropdown[k] = !this.dropdown[k];
  1085. },
  1086. pickOption(k, v) {
  1087. if (k === "customer") {
  1088. if (!Array.isArray(this.form.customer)) this.form.customer = [];
  1089. const idx = this.form.customer.indexOf(v);
  1090. if (idx === -1) {
  1091. this.form.customer.push(v);
  1092. } else {
  1093. this.form.customer.splice(idx, 1);
  1094. }
  1095. return;
  1096. }
  1097. this.form[k] = v;
  1098. if (k === "product") {
  1099. this.form.pkgSpec = "";
  1100. this.getGuigeList(v.physicName);
  1101. }
  1102. this.dropdown[k] = false;
  1103. },
  1104. isCustomerSelected(name) {
  1105. const arr = this.form.customer;
  1106. if (!Array.isArray(arr)) return false;
  1107. return arr.some((i) => i.customerName === name);
  1108. },
  1109. removeCustomer(name) {
  1110. if (!Array.isArray(this.form.customer)) return;
  1111. const idx = this.form.customer.findIndex((i) => i.customerName === name);
  1112. if (idx !== -1) this.form.customer.splice(idx, 1);
  1113. },
  1114. clearAllCustomers() {
  1115. this.form.customer = [];
  1116. },
  1117. filteredOptions(k, type) {
  1118. const arr = this.options[k] || [];
  1119. let q = "";
  1120. if (type === "filter") {
  1121. q = this.filterSearchForm[k] || "";
  1122. } else {
  1123. q = this.searchForm[k] || "";
  1124. }
  1125. q = String(q).trim().toLocaleLowerCase();
  1126. if (!q) return arr;
  1127. return arr.filter((it) => {
  1128. if (typeof it === "string")
  1129. return it.toLocaleLowerCase().indexOf(q) !== -1;
  1130. if (it && typeof it === "object") {
  1131. const name =
  1132. k === "region"
  1133. ? it.regionName || it.name || ""
  1134. : it.physicName || it.productName || "";
  1135. return String(name).toLocaleLowerCase().indexOf(q) !== -1;
  1136. }
  1137. return false;
  1138. });
  1139. },
  1140. // Initialize product list for pagination
  1141. initProductList(mode) {
  1142. const allProducts = this.filteredOptions(
  1143. "product",
  1144. mode === "filter" ? "filter" : undefined,
  1145. );
  1146. const res = getPaginatedList({
  1147. page: 0,
  1148. size: 10,
  1149. initData: allProducts,
  1150. data: [],
  1151. });
  1152. if (mode === "filter") {
  1153. this.filterProductPage = res.page;
  1154. this.filterDisplayProducts = res.data;
  1155. } else {
  1156. this.productPage = res.page;
  1157. this.displayProducts = res.data;
  1158. }
  1159. },
  1160. // Load more products on scroll
  1161. loadMoreProducts(mode) {
  1162. const allProducts = this.filteredOptions(
  1163. "product",
  1164. mode === "filter" ? "filter" : undefined,
  1165. );
  1166. const isFilter = mode === "filter";
  1167. const currentPage = isFilter ? this.filterProductPage : this.productPage;
  1168. const currentData = isFilter
  1169. ? this.filterDisplayProducts
  1170. : this.displayProducts;
  1171. const res = getPaginatedList({
  1172. page: currentPage,
  1173. size: 10,
  1174. initData: allProducts,
  1175. data: currentData,
  1176. });
  1177. if (res.data) {
  1178. if (isFilter) {
  1179. this.filterProductPage = res.page;
  1180. this.filterDisplayProducts = res.data;
  1181. } else {
  1182. this.productPage = res.page;
  1183. this.displayProducts = res.data;
  1184. }
  1185. }
  1186. },
  1187. onSearchFocus() {
  1188. this.dropdownUpward = true;
  1189. },
  1190. onSearchBlur() {
  1191. this.dropdownUpward = false;
  1192. },
  1193. dropdownPosStyle() {
  1194. // if (this.dropdownUpward) {
  1195. // return { bottom: "84rpx" };
  1196. // }
  1197. return { top: "84rpx" };
  1198. },
  1199. openDatePicker() {
  1200. if (this.modalType === "read") return;
  1201. this.$refs.datePicker.show();
  1202. },
  1203. onDateChange(val) {
  1204. const arr = Array.isArray(val) ? val : this.dateRange;
  1205. if (!Array.isArray(arr) || arr.length !== 2) return;
  1206. const startDate = new Date(arr[0].replace(/-/g, "/"));
  1207. const endDate = new Date(arr[1].replace(/-/g, "/"));
  1208. const diff = endDate.getTime() - startDate.getTime();
  1209. const limit = 183 * 24 * 3600 * 1000; // Approx 6 months
  1210. if (diff > limit) {
  1211. uni.showToast({
  1212. title: "时间范围不能超过半年",
  1213. icon: "none",
  1214. });
  1215. this.dateRange = [];
  1216. return;
  1217. }
  1218. this.dateRange = [
  1219. this.normalizeDateToYMD(arr[0]),
  1220. this.normalizeDateToYMD(arr[1]),
  1221. ];
  1222. },
  1223. onStart(item) {
  1224. uni.showModal({
  1225. title: "是否开始导出报表?",
  1226. success: (res) => {
  1227. if (res.confirm) {
  1228. uni.showLoading();
  1229. request("/report/confirm", {
  1230. id: item?.id || "",
  1231. path: "reportExport/index.vue",
  1232. }).then((res) => {
  1233. uni.hideLoading();
  1234. if (res.code == 200) {
  1235. uni.showToast({
  1236. title: "已开始导出",
  1237. icon: "none",
  1238. duration: 2000,
  1239. });
  1240. this.resetFetch();
  1241. this.closeCreate();
  1242. } else {
  1243. uni.showToast({
  1244. title: res?.msg || "请求失败",
  1245. icon: "none",
  1246. duration: 2000,
  1247. });
  1248. }
  1249. });
  1250. }
  1251. },
  1252. });
  1253. },
  1254. onSend(item) {
  1255. this.currentItem = item;
  1256. this.emailError = false;
  1257. this.emailModalOpen = true;
  1258. },
  1259. closeEmailModal() {
  1260. this.emailModalOpen = false;
  1261. },
  1262. handleSendEmail() {
  1263. const email = String(this.emailForm.email || "").trim();
  1264. if (!email) {
  1265. this.emailError = true;
  1266. return;
  1267. }
  1268. this.closeEmailModal();
  1269. uni.showLoading({
  1270. title: "发送中...",
  1271. });
  1272. const url = "/report/sendemail";
  1273. request(url, {
  1274. taskId: this.currentItem?.id,
  1275. emailAddress: email + "@999.com.cn",
  1276. path: "reportExport/index.vue",
  1277. }).then((res) => {
  1278. uni.hideLoading();
  1279. if (res.code === 200) {
  1280. uni.showToast({
  1281. title: "发送成功",
  1282. icon: "none",
  1283. duration: 2000,
  1284. });
  1285. } else {
  1286. uni.showToast({
  1287. title: res?.msg || "发送失败",
  1288. icon: "none",
  1289. duration: 2000,
  1290. });
  1291. }
  1292. });
  1293. },
  1294. onScrollToLower() {
  1295. // if (this.isLoading) return;
  1296. // if (this.list.length >= this.totalCount) return;
  1297. // this.isLoading = true;
  1298. // const remain = this.totalCount - this.list.length;
  1299. // const toAdd = Math.min(10, remain);
  1300. // setTimeout(() => {
  1301. // const more = this.genItems(toAdd);
  1302. // this.list = this.list.concat(more);
  1303. // this.animateNew(more);
  1304. // this.isLoading = false;
  1305. // }, 800);
  1306. this.fetchList();
  1307. },
  1308. genItems(n) {
  1309. const res = [];
  1310. const base = this.list.length;
  1311. for (let i = 0; i < n; i++) {
  1312. const idx = base + i + 1;
  1313. const statusIdx = idx % 3;
  1314. const target = [60, 0, 100][statusIdx];
  1315. const sText = ["导出进行中", "导出待开始", "导出已完成"][statusIdx];
  1316. const sClass = ["ing", "wait", "done"][statusIdx];
  1317. const action = ["", "start", "done"][statusIdx];
  1318. res.push({
  1319. title: `第${idx}条公司报表`,
  1320. product: "感冒灵",
  1321. range: "2025-11-27—2025-12-27",
  1322. statusText: sText,
  1323. statusClass: sClass,
  1324. showProgress: statusIdx !== 1,
  1325. progress: 0,
  1326. progressTarget: target,
  1327. action,
  1328. });
  1329. }
  1330. return res;
  1331. },
  1332. // animateAll() {
  1333. // this.list.forEach((it) => this.animateItem(it));
  1334. // },
  1335. // animateNew(arr) {
  1336. // arr.forEach((it) => this.animateItem(it));
  1337. // },
  1338. // animateItem(item) {
  1339. // if (!item.showProgress) return;
  1340. // item.progress = 60;
  1341. // const target = Number(item.progressTarget) || 0;
  1342. // const step = Math.max(1, Math.round(target / 60));
  1343. // const timer = setInterval(() => {
  1344. // item.progress += step;
  1345. // if (item.progress >= target) {
  1346. // item.progress = target;
  1347. // clearInterval(timer);
  1348. // }
  1349. // }, 16);
  1350. // },
  1351. },
  1352. };
  1353. </script>
  1354. <style>
  1355. .report-export-page {
  1356. position: relative;
  1357. box-sizing: border-box;
  1358. /* padding: 170rpx 0 calc(50rpx + env(safe-area-inset-bottom)); */
  1359. padding-top: 290rpx;
  1360. }
  1361. .report-export-search-bar-container {
  1362. position: fixed;
  1363. top: 100rpx;
  1364. left: 0;
  1365. padding: 24rpx 24rpx 16rpx;
  1366. background-color: #f3f6f9;
  1367. z-index: 10;
  1368. box-sizing: border-box;
  1369. width: 100%;
  1370. }
  1371. .report-export-search-bar {
  1372. display: flex;
  1373. align-items: center;
  1374. background: #fff;
  1375. border-radius: 16rpx;
  1376. padding: 16rpx;
  1377. }
  1378. .report-export-search-input-wrap {
  1379. flex: 1;
  1380. position: relative;
  1381. background: #f3f6f9;
  1382. border-radius: 40rpx;
  1383. display: flex;
  1384. align-items: center;
  1385. height: 90rpx;
  1386. padding: 0 12rpx;
  1387. }
  1388. .report-export-search-icon {
  1389. width: 28rpx;
  1390. height: 28rpx;
  1391. margin-left: 16rpx;
  1392. }
  1393. .report-export-search-input {
  1394. flex: 1;
  1395. height: 90rpx;
  1396. padding: 0 16rpx;
  1397. font-size: 28rpx;
  1398. }
  1399. .report-export-search-btn {
  1400. height: 72rpx;
  1401. line-height: 72rpx;
  1402. padding: 0 34rpx;
  1403. border-radius: 36rpx;
  1404. background: #2c69ff;
  1405. color: #fff;
  1406. font-size: 34rpx;
  1407. margin-left: 12rpx;
  1408. }
  1409. .report-export-filter-btn {
  1410. margin-left: 12rpx;
  1411. display: flex;
  1412. flex-direction: column;
  1413. align-items: center;
  1414. justify-content: center;
  1415. }
  1416. .report-export-filter-icon {
  1417. width: 40rpx;
  1418. height: 40rpx;
  1419. }
  1420. .report-export-filter-text {
  1421. margin-top: 8rpx;
  1422. font-size: 24rpx;
  1423. color: #2c69ff;
  1424. }
  1425. .scan-rate-ranges-container {
  1426. position: fixed;
  1427. top: 262rpx;
  1428. left: 0;
  1429. width: 100%;
  1430. height: 120rpx;
  1431. background: #f3f6f9;
  1432. z-index: 6;
  1433. }
  1434. .scan-rate-ranges {
  1435. padding: 0rpx 24rpx 20rpx;
  1436. }
  1437. .scan-rate-ranges-content {
  1438. display: flex;
  1439. background: #fff;
  1440. padding: 20rpx 30rpx;
  1441. border-radius: 16rpx;
  1442. justify-content: space-between;
  1443. }
  1444. .scan-rate-range {
  1445. padding: 12rpx 35rpx;
  1446. border-radius: 5rpx;
  1447. background: rgb(240, 240, 240);
  1448. font-size: 26rpx;
  1449. }
  1450. .scan-rate-range.scan-rate-active {
  1451. background: #2c69ff;
  1452. color: #fff;
  1453. }
  1454. .report-export-list-scroll {
  1455. position: fixed;
  1456. top: 380rpx;
  1457. left: 0;
  1458. box-sizing: border-box;
  1459. width: 100%;
  1460. padding: 0 24rpx;
  1461. padding-bottom: calc(env(safe-area-inset-bottom) + 50rpx);
  1462. box-sizing: border-box;
  1463. }
  1464. .report-export-item-card {
  1465. background: #fff;
  1466. border-radius: 16rpx;
  1467. padding: 24rpx;
  1468. margin-bottom: 16rpx;
  1469. }
  1470. .report-export-item-header {
  1471. width: 100%;
  1472. display: flex;
  1473. align-items: flex-start;
  1474. flex-wrap: wrap;
  1475. }
  1476. .report-export-item-title {
  1477. flex: 1;
  1478. width: 0;
  1479. word-break: break-word;
  1480. margin-right: 20rpx;
  1481. font-size: 38rpx;
  1482. color: #2c69ff;
  1483. display: -webkit-box;
  1484. -webkit-box-orient: vertical;
  1485. -webkit-line-clamp: 2;
  1486. overflow: hidden;
  1487. text-decoration: underline;
  1488. }
  1489. .report-export-status {
  1490. flex-shrink: 0;
  1491. padding: 2rpx 10rpx;
  1492. border-radius: 6rpx;
  1493. font-size: 22rpx;
  1494. border: 1rpx solid transparent;
  1495. }
  1496. .report-export-status.report-export-status-2 {
  1497. background: rgba(103, 194, 58, 0.1);
  1498. border-color: rgba(103, 194, 58, 0.2);
  1499. color: #67c23a;
  1500. }
  1501. .report-export-status.report-export-status-1 {
  1502. background: rgba(136, 136, 136, 0.1);
  1503. border-color: rgba(136, 136, 136, 0.2);
  1504. color: #888;
  1505. }
  1506. .report-export-status.report-export-status-3,
  1507. .report-export-status.report-export-status-4 {
  1508. background: rgba(44, 105, 255, 0.1);
  1509. border-color: rgba(44, 105, 255, 0.2);
  1510. color: #2c69ff;
  1511. }
  1512. .report-export-item-row {
  1513. margin-top: 12rpx;
  1514. font-size: 28rpx;
  1515. color: #999;
  1516. }
  1517. .report-export-progress-wrap {
  1518. margin-top: 20rpx;
  1519. }
  1520. .report-export-progress {
  1521. margin-top: 8rpx;
  1522. height: 32rpx;
  1523. background: #e6ebf5;
  1524. border-radius: 999rpx;
  1525. overflow: hidden;
  1526. position: relative;
  1527. }
  1528. .report-export-progress-fill {
  1529. position: absolute;
  1530. left: 0;
  1531. top: 0;
  1532. height: 100%;
  1533. background: #2c69ff;
  1534. border-radius: 999rpx;
  1535. width: 0;
  1536. transition: width 0.2s linear;
  1537. }
  1538. .report-export-progress-text {
  1539. position: absolute;
  1540. left: 50%;
  1541. top: 50%;
  1542. transform: translate(-50%, -50%);
  1543. font-size: 26rpx;
  1544. color: #fff;
  1545. z-index: 2;
  1546. }
  1547. .report-export-action-row {
  1548. margin-top: 16rpx;
  1549. display: flex;
  1550. align-items: center;
  1551. justify-content: flex-end;
  1552. }
  1553. .report-export-action-btn {
  1554. height: 50rpx;
  1555. line-height: 50rpx;
  1556. padding: 0 28rpx;
  1557. border-radius: 12rpx;
  1558. font-size: 30rpx;
  1559. margin: 0;
  1560. }
  1561. .report-export-action-btn+.report-export-action-btn {
  1562. margin-left: 12rpx;
  1563. }
  1564. .report-export-action-btn.report-export-primary {
  1565. background: #2c69ff;
  1566. color: #fff;
  1567. }
  1568. .report-export-action-btn.report-export-info {
  1569. background: #67c23a;
  1570. color: #fff;
  1571. }
  1572. .report-export-loading-row {
  1573. justify-content: center;
  1574. }
  1575. .report-export-loading-wrapper {
  1576. width: 100%;
  1577. height: 76rpx;
  1578. display: flex;
  1579. align-items: center;
  1580. justify-content: center;
  1581. }
  1582. .report-export-loading-icon {
  1583. width: 40rpx;
  1584. height: 40rpx;
  1585. animation: spin 1s linear infinite;
  1586. }
  1587. @keyframes spin {
  1588. from {
  1589. transform: rotate(0deg);
  1590. }
  1591. to {
  1592. transform: rotate(360deg);
  1593. }
  1594. }
  1595. .report-export-footer {
  1596. position: fixed;
  1597. left: 0;
  1598. right: 0;
  1599. bottom: 0;
  1600. padding: 12rpx 30rpx calc(50rpx + env(safe-area-inset-bottom));
  1601. background: #fff;
  1602. }
  1603. .report-export-footer-btn {
  1604. height: 86rpx;
  1605. border-radius: 999rpx;
  1606. background: #2c69ff;
  1607. color: #fff;
  1608. display: flex;
  1609. align-items: center;
  1610. justify-content: center;
  1611. font-size: 30rpx;
  1612. box-shadow: 0 8rpx 24rpx rgba(44, 105, 255, 0.35);
  1613. }
  1614. .report-export-create-modal-mask {
  1615. position: fixed;
  1616. left: 0;
  1617. right: 0;
  1618. top: 0;
  1619. bottom: 0;
  1620. background: rgba(0, 0, 0, 0.35);
  1621. z-index: 90;
  1622. }
  1623. .report-export-create-modal {
  1624. position: fixed;
  1625. left: 0;
  1626. right: 0;
  1627. bottom: -100%;
  1628. width: 100%;
  1629. background: #fff;
  1630. border-top-left-radius: 45rpx;
  1631. border-top-right-radius: 45rpx;
  1632. z-index: 92;
  1633. box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.12);
  1634. /* transform: translateY(100%); */
  1635. transition: bottom 0.25s ease-out;
  1636. }
  1637. .report-export-create-modal--open {
  1638. /* transform: translateY(0) !important; */
  1639. bottom: 0 !important;
  1640. }
  1641. .report-export-create-modal-title {
  1642. position: relative;
  1643. padding: 28rpx 28rpx 12rpx;
  1644. font-size: 34rpx;
  1645. color: #333;
  1646. text-align: center;
  1647. line-height: 60rpx;
  1648. font-weight: 500;
  1649. }
  1650. .report-export-create-modal-close {
  1651. position: absolute;
  1652. right: 32rpx;
  1653. top: 50%;
  1654. transform: translateY(-50%);
  1655. padding: 10rpx;
  1656. color: #909399;
  1657. font-size: 55rpx;
  1658. line-height: 1;
  1659. }
  1660. .report-export-create-modal-body {
  1661. padding: 0 32rpx 100rpx;
  1662. }
  1663. .report-export-create-modal-row {
  1664. display: flex;
  1665. flex-direction: column;
  1666. margin-top: 32rpx;
  1667. position: relative;
  1668. }
  1669. .report-export-create-modal-label {
  1670. width: auto;
  1671. font-size: 28rpx;
  1672. color: #333;
  1673. margin-bottom: 16rpx;
  1674. font-weight: 500;
  1675. }
  1676. .report-export-create-modal-inputwrap {
  1677. flex: 1;
  1678. position: relative;
  1679. border: 1rpx solid #dcdfe6;
  1680. border-radius: 12rpx;
  1681. display: flex;
  1682. align-items: center;
  1683. min-height: 80rpx;
  1684. padding: 0 24rpx;
  1685. background-color: #fff;
  1686. }
  1687. .report-export-create-modal-static {
  1688. position: relative;
  1689. flex: 1;
  1690. max-height: 115rpx;
  1691. font-size: 28rpx;
  1692. color: #606266;
  1693. line-height: 40rpx;
  1694. padding: 20rpx 0;
  1695. overflow-y: auto;
  1696. padding-right: 20rpx;
  1697. }
  1698. .report-export-input-simulator {
  1699. display: flex;
  1700. justify-content: center;
  1701. align-items: center;
  1702. }
  1703. .report-export-create-modal-input {
  1704. flex: 1;
  1705. height: 80rpx;
  1706. font-size: 28rpx;
  1707. color: #606266;
  1708. }
  1709. .report-export-dropdown-other-customer-input {
  1710. color: #666;
  1711. }
  1712. /* .report-export-create-modal-select-arrow {
  1713. width: 18rpx;
  1714. height: 18rpx;
  1715. border: 5rpx solid #999;
  1716. border-top: none;
  1717. border-left: none;
  1718. transform: rotate(45deg);
  1719. margin: 0 8rpx 10rpx 12rpx;
  1720. }
  1721. .report-export-create-modal-select-arrow.disabled {
  1722. opacity: 0.4;
  1723. pointer-events: none;
  1724. } */
  1725. .report-export-create-modal-dropdown {
  1726. position: absolute;
  1727. left: 0;
  1728. right: 0;
  1729. background: #fff;
  1730. border: 1rpx solid #eef0f4;
  1731. border-radius: 12rpx;
  1732. box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
  1733. z-index: 6;
  1734. max-height: 510rpx;
  1735. overflow-y: auto;
  1736. -webkit-overflow-scrolling: touch;
  1737. }
  1738. .report-export-create-modal-dropdown-list {
  1739. max-height: 350rpx;
  1740. }
  1741. .report-export-dropdown-search-row {
  1742. padding: 10rpx;
  1743. }
  1744. .report-export-dropdown-search-input {
  1745. width: 100%;
  1746. height: 60rpx;
  1747. border: 1rpx solid #eaeef4;
  1748. border-radius: 8rpx;
  1749. box-sizing: border-box;
  1750. padding: 0 16rpx;
  1751. font-size: 28rpx;
  1752. }
  1753. .report-export-create-modal-dropdown-item {
  1754. padding: 16rpx 20rpx;
  1755. font-size: 28rpx;
  1756. color: #333;
  1757. }
  1758. .report-export-selected {
  1759. background: #f0f5ff;
  1760. }
  1761. .report-export-input-arrow {
  1762. width: 16rpx;
  1763. height: 16rpx;
  1764. border-right: 3rpx solid #c0c4cc;
  1765. border-bottom: 3rpx solid #c0c4cc;
  1766. transform: rotate(45deg);
  1767. margin-top: -6rpx;
  1768. }
  1769. .customer-chip {
  1770. display: inline-block;
  1771. position: relative;
  1772. line-height: 50rpx;
  1773. border: 1rpx solid #eaeef4;
  1774. border-radius: 8rpx;
  1775. padding: 0rpx 44rpx 0rpx 16rpx;
  1776. margin-right: 8rpx;
  1777. margin-bottom: 8rpx;
  1778. font-size: 22rpx;
  1779. color: #333;
  1780. }
  1781. .customer-chip-close {
  1782. position: absolute;
  1783. right: 6rpx;
  1784. top: 0;
  1785. color: #666;
  1786. font-size: 28rpx;
  1787. padding: 0 8rpx;
  1788. border-radius: 6rpx;
  1789. }
  1790. .customer-clear-all {
  1791. position: absolute;
  1792. right: 6rpx;
  1793. top: 50%;
  1794. transform: translateY(-50%);
  1795. line-height: 50rpx;
  1796. padding: 8rpx 10rpx;
  1797. font-size: 40rpx;
  1798. }
  1799. .report-export-create-modal-estimated {
  1800. font-size: 28rpx;
  1801. color: #666;
  1802. }
  1803. .report-export-create-modal-footer {
  1804. padding: 18rpx 28rpx calc(50rpx + env(safe-area-inset-bottom));
  1805. }
  1806. .report-export-create-modal-btn {
  1807. line-height: 90rpx;
  1808. border-radius: 20rpx;
  1809. background: #2c69ff;
  1810. color: #fff;
  1811. text-align: center;
  1812. font-size: 30rpx;
  1813. }
  1814. .report-export-create-email-modal {
  1815. /* transform: translateY(200%); */
  1816. height: 420rpx;
  1817. top: 30%;
  1818. bottom: auto;
  1819. border-radius: 16rpx;
  1820. width: 600rpx;
  1821. left: 75rpx;
  1822. }
  1823. .report-export-email-input-wrap {
  1824. display: flex;
  1825. align-items: center;
  1826. background: #f5f7fa;
  1827. border-radius: 8rpx;
  1828. padding: 0 20rpx;
  1829. height: 80rpx;
  1830. border: 1rpx solid transparent;
  1831. }
  1832. .report-export-input-error {
  1833. border-color: #ff4d4f;
  1834. }
  1835. .report-export-email-input {
  1836. flex: 1;
  1837. font-size: 28rpx;
  1838. color: #333;
  1839. height: 100%;
  1840. }
  1841. .report-export-email-suffix {
  1842. font-size: 28rpx;
  1843. color: #333;
  1844. margin-left: 10rpx;
  1845. }
  1846. .report-export-error-text {
  1847. font-size: 24rpx;
  1848. color: #ff4d4f;
  1849. margin-top: 10rpx;
  1850. display: block;
  1851. }
  1852. .report-export-input-disabled {
  1853. background-color: #f5f7fa;
  1854. cursor: not-allowed;
  1855. opacity: 0.7;
  1856. }
  1857. </style>