index.vue 50 KB

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