index.vue 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683
  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. taskType: statusMap?.[this.filterForm?.status] || "",
  622. drugEntBaseInfoId: this.filterForm?.product?.drugEntBaseInfoId,
  623. beginTime: this.filterDateRange[0],
  624. endTime: this.filterDateRange[1],
  625. customerName: this.keyword || "",
  626. pageNum: this.pageNum,
  627. pageSize: this.pageSize,
  628. path: "reportExport/index.vue",
  629. }).then((res) => {
  630. if (res.code == 200) {
  631. const _data = res.data || {};
  632. const { list, total } = _data;
  633. this.totalCount = total || 0;
  634. this.list = Array.isArray(list)
  635. ? [...this.list, ...list]
  636. : [...this.list];
  637. if (this.list.length < this.totalCount) {
  638. this.hasmore = true;
  639. this.pageNum++;
  640. } else {
  641. this.hasmore = false;
  642. }
  643. // this.list.push({
  644. // ...this.list[1],
  645. // status: 3,
  646. // });
  647. this.list.push({
  648. ...this.list[0],
  649. finishTime: "2025-12-15",
  650. status: 3,
  651. });
  652. // this.animateAll();
  653. }
  654. this.fetchLoading = false;
  655. this.loading = false;
  656. });
  657. },
  658. resetFetch() {
  659. this.loading = true;
  660. this.list = [];
  661. this.pageNum = 1;
  662. this.hasmore = true;
  663. this.fetchList();
  664. },
  665. toDetail(item) {
  666. uni.navigateTo({
  667. url: `/packages/traceabilityReport/pages/reportExport/detail/index?id=${item.id
  668. }&title=${encodeURIComponent(
  669. this.getCustomerName(item.customerName)
  670. )}`,
  671. });
  672. },
  673. onSearch() {
  674. this.resetFetch();
  675. },
  676. onCreate() {
  677. this.modalType = "create";
  678. this.taskTitle = "创建任务";
  679. this.createModalOpen = true;
  680. },
  681. closeCreate() {
  682. this.filterModalOpen = false;
  683. this.createModalOpen = false;
  684. this.closeDropdownAll();
  685. this.form = {
  686. region: { regionName: "" },
  687. customerType: "",
  688. customer: [],
  689. product: { physicName: "" },
  690. // otherCustomer: "",
  691. };
  692. this.searchForm = {
  693. region: "",
  694. product: "",
  695. };
  696. this.dateRange = [];
  697. if (this.computeTimer) {
  698. clearTimeout(this.computeTimer);
  699. this.computeTimer = null;
  700. }
  701. },
  702. confirmCreate() {
  703. let flag = false;
  704. Object.values(this.dropdown).forEach((v) => {
  705. if (v) {
  706. flag = true;
  707. }
  708. });
  709. if (flag) {
  710. this.closeDropdownAll();
  711. return;
  712. }
  713. if (!this.isFormComplete()) {
  714. uni.showToast({ title: "请完整填写任务内容", icon: "none" });
  715. return;
  716. }
  717. // uni.showToast({ title: "已创建", icon: "none" });
  718. uni.showLoading({
  719. title: this.modalType === "create" ? "创建中..." : "修改中...",
  720. });
  721. const url =
  722. this.modalType === "create" ? `/report/save` : `/report/update`;
  723. const customerId = (this.form?.customer || [])
  724. .map((v) => v?.customerCode || "")
  725. .join(",");
  726. const customerName = (this.form?.customer || [])
  727. .map((v) => v?.customerName || "")
  728. .join(",");
  729. request(url, {
  730. id:
  731. this.modalType === "create" ? undefined : this.currentItem?.id || "",
  732. regionCode: this.form?.region?.regionCode || "",
  733. customerType: customerTypeMap?.[this.form?.customerType] || "",
  734. customerId,
  735. customerName,
  736. // otherCustomer: this.form?.otherCustomer || "",
  737. drugEntBaseInfoId: this.form?.product?.drugEntBaseInfoId || "",
  738. beginTime: this.dateRange[0],
  739. endTime: this.dateRange[1],
  740. path: "",
  741. }).then((res) => {
  742. if (res.code == 200) {
  743. uni.hideLoading();
  744. uni.showToast({
  745. title: this.modalType === "create" ? "已创建" : "已修改",
  746. icon: "none",
  747. });
  748. this.resetFetch();
  749. this.closeCreate();
  750. }
  751. });
  752. },
  753. isFormComplete() {
  754. const f = this.form;
  755. const drOk =
  756. Array.isArray(this.dateRange) &&
  757. this.dateRange.length === 2 &&
  758. this.dateRange[0] &&
  759. this.dateRange[1];
  760. let customerOk = Array.isArray(f.customer)
  761. ? f.customer.length > 0
  762. : !!f.customer;
  763. return (
  764. f.region?.regionName &&
  765. f.customerType &&
  766. customerOk &&
  767. f.product?.physicName &&
  768. drOk
  769. );
  770. },
  771. confirmDelete() {
  772. uni.showModal({
  773. title: "确认删除吗?",
  774. success: (res) => {
  775. if (res.confirm) {
  776. uni.showLoading();
  777. request("/report/delete", {
  778. id: this.currentItem?.id || "",
  779. path: "reportExport/index.vue",
  780. }).then((res) => {
  781. uni.hideLoading();
  782. if (res.code == 200) {
  783. uni.showToast({
  784. title: "删除成功",
  785. icon: "none",
  786. duration: 2000,
  787. });
  788. this.resetFetch();
  789. } else {
  790. uni.showToast({
  791. title: res?.msg || "删除失败",
  792. icon: "none",
  793. duration: 2000,
  794. });
  795. }
  796. });
  797. }
  798. },
  799. });
  800. },
  801. onInput(k) {
  802. this.closeDropdownAll();
  803. this.dropdown[k] = true;
  804. if (k === "customer") {
  805. this.customerPage = 1;
  806. this.customerTotal = null;
  807. this.customerHasMore = true;
  808. this.customers = [];
  809. if (this.customerDebounceTimer)
  810. clearTimeout(this.customerDebounceTimer);
  811. this.customerDebounceTimer = setTimeout(() => {
  812. this.getCustomerOptions();
  813. }, 500);
  814. return;
  815. }
  816. if (k === "product") {
  817. this.initProductList('create');
  818. }
  819. },
  820. closeDropdownAll() {
  821. this.dropdown = {
  822. region: false,
  823. customerType: false,
  824. customer: false,
  825. product: false,
  826. };
  827. this.filterDropdown.product = false;
  828. },
  829. openFilterDropdown(k) {
  830. this.closeDropdownAll();
  831. this.filterDropdown[k] = true;
  832. if (k === "product") {
  833. this.initProductList('filter');
  834. }
  835. },
  836. toggleFilterDropdown(k) {
  837. this.filterDropdown[k] = !this.filterDropdown[k];
  838. },
  839. onFilterInput(k) {
  840. this.closeDropdownAll();
  841. this.filterDropdown[k] = true;
  842. if (k === "product") {
  843. this.initProductList('filter');
  844. }
  845. },
  846. pickFilterOption(k, v) {
  847. if (["status"].includes(k) && this.filterForm[k] === v) {
  848. this.filterForm[k] = "";
  849. this.filterDropdown[k] = false;
  850. return;
  851. }
  852. this.filterForm[k] = v;
  853. this.filterDropdown[k] = false;
  854. },
  855. filteredFilterOptions(k) {
  856. const arr = k === "product" ? this.products || [] : [];
  857. const q = String(this.filterForm[k] || "").trim();
  858. if (!q) return arr;
  859. return arr.filter((it) => it.indexOf(q) !== -1);
  860. },
  861. onFilterDateChange() { },
  862. confirmFilter() {
  863. this.filterModalOpen = false;
  864. },
  865. openDropdown(k) {
  866. this.closeDropdownAll();
  867. this.dropdown[k] = true;
  868. if (k === "customer") {
  869. if (!this.customers || this.customers.length === 0) {
  870. this.customerPage = 1;
  871. this.customerTotal = null;
  872. this.customerHasMore = true;
  873. this.getCustomerOptions();
  874. }
  875. }
  876. if (k === "product") {
  877. this.initProductList('create');
  878. }
  879. },
  880. toggleDropdown(k) {
  881. this.dropdown[k] = !this.dropdown[k];
  882. },
  883. pickOption(k, v) {
  884. if (k === "customer") {
  885. if (!Array.isArray(this.form.customer)) this.form.customer = [];
  886. const idx = this.form.customer.indexOf(v);
  887. if (idx === -1) {
  888. this.form.customer.push(v);
  889. } else {
  890. this.form.customer.splice(idx, 1);
  891. }
  892. return;
  893. }
  894. this.form[k] = v;
  895. this.dropdown[k] = false;
  896. },
  897. isCustomerSelected(name) {
  898. const arr = this.form.customer;
  899. if (!Array.isArray(arr)) return false;
  900. return arr.some((i) => i.customerName === name);
  901. },
  902. removeCustomer(name) {
  903. if (!Array.isArray(this.form.customer)) return;
  904. const idx = this.form.customer.findIndex((i) => i.customerName === name);
  905. if (idx !== -1) this.form.customer.splice(idx, 1);
  906. },
  907. clearAllCustomers() {
  908. this.form.customer = [];
  909. },
  910. filteredOptions(k, type) {
  911. const arr = this.options[k] || [];
  912. let q = "";
  913. if (type === "filter") {
  914. q = this.filterSearchForm[k] || "";
  915. } else {
  916. q = this.searchForm[k] || "";
  917. }
  918. q = String(q).trim().toLocaleLowerCase();
  919. if (!q) return arr;
  920. return arr.filter((it) => {
  921. if (typeof it === "string")
  922. return it.toLocaleLowerCase().indexOf(q) !== -1;
  923. if (it && typeof it === "object") {
  924. const name =
  925. k === "region"
  926. ? it.regionName || it.name || ""
  927. : it.physicName || it.productName || "";
  928. return String(name).toLocaleLowerCase().indexOf(q) !== -1;
  929. }
  930. return false;
  931. });
  932. },
  933. // Initialize product list for pagination
  934. initProductList(mode) {
  935. const allProducts = this.filteredOptions('product', mode === 'filter' ? 'filter' : undefined);
  936. const res = getPaginatedList({
  937. page: 0,
  938. size: 10,
  939. initData: allProducts,
  940. data: []
  941. });
  942. if (mode === 'filter') {
  943. this.filterProductPage = res.page;
  944. this.filterDisplayProducts = res.data;
  945. } else {
  946. this.productPage = res.page;
  947. this.displayProducts = res.data;
  948. }
  949. },
  950. // Load more products on scroll
  951. loadMoreProducts(mode) {
  952. const allProducts = this.filteredOptions('product', mode === 'filter' ? 'filter' : undefined);
  953. const isFilter = mode === 'filter';
  954. const currentPage = isFilter ? this.filterProductPage : this.productPage;
  955. const currentData = isFilter ? this.filterDisplayProducts : this.displayProducts;
  956. const res = getPaginatedList({
  957. page: currentPage,
  958. size: 10,
  959. initData: allProducts,
  960. data: currentData
  961. });
  962. if (res.data) {
  963. if (isFilter) {
  964. this.filterProductPage = res.page;
  965. this.filterDisplayProducts = res.data;
  966. } else {
  967. this.productPage = res.page;
  968. this.displayProducts = res.data;
  969. }
  970. }
  971. },
  972. onSearchFocus() {
  973. this.dropdownUpward = true;
  974. },
  975. onSearchBlur() {
  976. this.dropdownUpward = false;
  977. },
  978. dropdownPosStyle() {
  979. // if (this.dropdownUpward) {
  980. // return { bottom: "84rpx" };
  981. // }
  982. return { top: "84rpx" };
  983. },
  984. onDateChange() { },
  985. onStart(item) {
  986. uni.showModal({
  987. title: "是否开始导出报表?",
  988. success: (res) => {
  989. if (res.confirm) {
  990. uni.showLoading();
  991. request("/report/confirm", {
  992. id: item?.id || "",
  993. path: "reportExport/index.vue",
  994. }).then((res) => {
  995. uni.hideLoading();
  996. if (res.code == 200) {
  997. uni.showToast({
  998. title: "已开始导出",
  999. icon: "none",
  1000. duration: 2000,
  1001. });
  1002. this.resetFetch();
  1003. this.closeCreate();
  1004. } else {
  1005. uni.showToast({
  1006. title: res?.msg || "请求失败",
  1007. icon: "none",
  1008. duration: 2000,
  1009. });
  1010. }
  1011. });
  1012. }
  1013. },
  1014. });
  1015. },
  1016. onSend(item) {
  1017. this.currentItem = item;
  1018. this.emailError = false;
  1019. this.emailModalOpen = true;
  1020. },
  1021. closeEmailModal() {
  1022. this.emailModalOpen = false;
  1023. },
  1024. handleSendEmail() {
  1025. const email = String(this.emailForm.email || '').trim()
  1026. if (!email) {
  1027. this.emailError = true;
  1028. return;
  1029. }
  1030. this.closeEmailModal();
  1031. uni.showLoading({
  1032. title: "发送中...",
  1033. });
  1034. const url = "/report/sendEmail";
  1035. request(url, {
  1036. taskId: this.currentItem?.id,
  1037. emailAddress: email + "@999.com.cn",
  1038. path: "reportExport/index.vue",
  1039. }).then((res) => {
  1040. uni.hideLoading();
  1041. if (res.code === 200) {
  1042. uni.showToast({
  1043. title: "发送成功",
  1044. icon: "none",
  1045. duration: 2000,
  1046. });
  1047. } else {
  1048. uni.showToast({
  1049. title: res?.msg || "发送失败",
  1050. icon: "none",
  1051. duration: 2000,
  1052. });
  1053. }
  1054. });
  1055. },
  1056. onScrollToLower() {
  1057. // if (this.isLoading) return;
  1058. // if (this.list.length >= this.totalCount) return;
  1059. // this.isLoading = true;
  1060. // const remain = this.totalCount - this.list.length;
  1061. // const toAdd = Math.min(10, remain);
  1062. // setTimeout(() => {
  1063. // const more = this.genItems(toAdd);
  1064. // this.list = this.list.concat(more);
  1065. // this.animateNew(more);
  1066. // this.isLoading = false;
  1067. // }, 800);
  1068. this.fetchList();
  1069. },
  1070. genItems(n) {
  1071. const res = [];
  1072. const base = this.list.length;
  1073. for (let i = 0; i < n; i++) {
  1074. const idx = base + i + 1;
  1075. const statusIdx = idx % 3;
  1076. const target = [60, 0, 100][statusIdx];
  1077. const sText = ["导出进行中", "导出待开始", "导出已完成"][statusIdx];
  1078. const sClass = ["ing", "wait", "done"][statusIdx];
  1079. const action = ["", "start", "done"][statusIdx];
  1080. res.push({
  1081. title: `第${idx}条公司报表`,
  1082. product: "感冒灵",
  1083. range: "2025-11-27—2025-12-27",
  1084. statusText: sText,
  1085. statusClass: sClass,
  1086. showProgress: statusIdx !== 1,
  1087. progress: 0,
  1088. progressTarget: target,
  1089. action,
  1090. });
  1091. }
  1092. return res;
  1093. },
  1094. // animateAll() {
  1095. // this.list.forEach((it) => this.animateItem(it));
  1096. // },
  1097. // animateNew(arr) {
  1098. // arr.forEach((it) => this.animateItem(it));
  1099. // },
  1100. // animateItem(item) {
  1101. // if (!item.showProgress) return;
  1102. // item.progress = 60;
  1103. // const target = Number(item.progressTarget) || 0;
  1104. // const step = Math.max(1, Math.round(target / 60));
  1105. // const timer = setInterval(() => {
  1106. // item.progress += step;
  1107. // if (item.progress >= target) {
  1108. // item.progress = target;
  1109. // clearInterval(timer);
  1110. // }
  1111. // }, 16);
  1112. // },
  1113. },
  1114. };
  1115. </script>
  1116. <style>
  1117. .report-export-page {
  1118. position: relative;
  1119. box-sizing: border-box;
  1120. /* padding: 170rpx 0 calc(50rpx + env(safe-area-inset-bottom)); */
  1121. padding-top: 290rpx;
  1122. }
  1123. .report-export-search-bar-container {
  1124. position: fixed;
  1125. top: 100rpx;
  1126. left: 0;
  1127. padding: 24rpx 24rpx 16rpx;
  1128. background-color: #f3f6f9;
  1129. z-index: 10;
  1130. box-sizing: border-box;
  1131. width: 100%;
  1132. }
  1133. .report-export-search-bar {
  1134. display: flex;
  1135. align-items: center;
  1136. background: #fff;
  1137. border-radius: 16rpx;
  1138. padding: 16rpx;
  1139. }
  1140. .report-export-search-input-wrap {
  1141. flex: 1;
  1142. position: relative;
  1143. background: #f3f6f9;
  1144. border-radius: 40rpx;
  1145. display: flex;
  1146. align-items: center;
  1147. height: 90rpx;
  1148. padding: 0 12rpx;
  1149. }
  1150. .report-export-search-icon {
  1151. width: 28rpx;
  1152. height: 28rpx;
  1153. margin-left: 16rpx;
  1154. }
  1155. .report-export-search-input {
  1156. flex: 1;
  1157. height: 90rpx;
  1158. padding: 0 16rpx;
  1159. font-size: 28rpx;
  1160. }
  1161. .report-export-search-btn {
  1162. height: 72rpx;
  1163. line-height: 72rpx;
  1164. padding: 0 34rpx;
  1165. border-radius: 36rpx;
  1166. background: #2c69ff;
  1167. color: #fff;
  1168. font-size: 34rpx;
  1169. margin-left: 12rpx;
  1170. }
  1171. .report-export-filter-btn {
  1172. margin-left: 12rpx;
  1173. display: flex;
  1174. flex-direction: column;
  1175. align-items: center;
  1176. justify-content: center;
  1177. }
  1178. .report-export-filter-icon {
  1179. width: 40rpx;
  1180. height: 40rpx;
  1181. }
  1182. .report-export-filter-text {
  1183. margin-top: 8rpx;
  1184. font-size: 24rpx;
  1185. color: #2c69ff;
  1186. }
  1187. .scan-rate-ranges-container {
  1188. position: fixed;
  1189. top: 262rpx;
  1190. left: 0;
  1191. width: 100%;
  1192. height: 120rpx;
  1193. background: #f3f6f9;
  1194. z-index: 6;
  1195. }
  1196. .scan-rate-ranges {
  1197. padding: 0rpx 24rpx 20rpx;
  1198. }
  1199. .scan-rate-ranges-content {
  1200. display: flex;
  1201. background: #fff;
  1202. padding: 20rpx 30rpx;
  1203. border-radius: 16rpx;
  1204. justify-content: space-between;
  1205. }
  1206. .scan-rate-range {
  1207. padding: 12rpx 35rpx;
  1208. border-radius: 5rpx;
  1209. background: rgb(240, 240, 240);
  1210. font-size: 26rpx;
  1211. }
  1212. .scan-rate-range.scan-rate-active {
  1213. background: #2c69ff;
  1214. color: #fff;
  1215. }
  1216. .report-export-list-scroll {
  1217. position: fixed;
  1218. top: 380rpx;
  1219. left: 0;
  1220. box-sizing: border-box;
  1221. width: 100%;
  1222. padding: 0 24rpx env(safe-area-inset-bottom);
  1223. box-sizing: border-box;
  1224. }
  1225. .report-export-item-card {
  1226. background: #fff;
  1227. border-radius: 16rpx;
  1228. padding: 24rpx;
  1229. margin-bottom: 16rpx;
  1230. }
  1231. .report-export-item-header {
  1232. width: 100%;
  1233. display: flex;
  1234. align-items: baseline;
  1235. flex-wrap: wrap;
  1236. }
  1237. .report-export-item-title {
  1238. flex: 1;
  1239. width: 0;
  1240. word-break: break-word;
  1241. margin-right: 20rpx;
  1242. font-size: 38rpx;
  1243. color: #2c69ff;
  1244. display: -webkit-box;
  1245. -webkit-box-orient: vertical;
  1246. -webkit-line-clamp: 2;
  1247. overflow: hidden;
  1248. }
  1249. .report-export-status {
  1250. flex-shrink: 0;
  1251. padding: 8rpx 12rpx;
  1252. border-radius: 10rpx;
  1253. font-size: 22rpx;
  1254. color: #fff;
  1255. }
  1256. .report-export-status.report-export-status-2 {
  1257. background: #67c23a;
  1258. }
  1259. .report-export-status.report-export-status-1 {
  1260. background: #888;
  1261. }
  1262. .report-export-status.report-export-status-3,
  1263. .report-export-status.report-export-status-4 {
  1264. background: #2c69ff;
  1265. }
  1266. .report-export-item-row {
  1267. margin-top: 12rpx;
  1268. font-size: 28rpx;
  1269. color: #999;
  1270. }
  1271. .report-export-progress-wrap {
  1272. margin-top: 20rpx;
  1273. }
  1274. .report-export-progress {
  1275. margin-top: 8rpx;
  1276. height: 32rpx;
  1277. background: #e6ebf5;
  1278. border-radius: 999rpx;
  1279. overflow: hidden;
  1280. position: relative;
  1281. }
  1282. .report-export-progress-fill {
  1283. position: absolute;
  1284. left: 0;
  1285. top: 0;
  1286. height: 100%;
  1287. background: #2c69ff;
  1288. border-radius: 999rpx;
  1289. width: 0;
  1290. transition: width 0.2s linear;
  1291. }
  1292. .report-export-progress-text {
  1293. position: absolute;
  1294. left: 50%;
  1295. top: 50%;
  1296. transform: translate(-50%, -50%);
  1297. font-size: 26rpx;
  1298. color: #fff;
  1299. z-index: 2;
  1300. }
  1301. .report-export-action-row {
  1302. margin-top: 16rpx;
  1303. display: flex;
  1304. align-items: center;
  1305. justify-content: flex-end;
  1306. }
  1307. .report-export-action-btn {
  1308. height: 50rpx;
  1309. line-height: 50rpx;
  1310. padding: 0 28rpx;
  1311. border-radius: 12rpx;
  1312. font-size: 30rpx;
  1313. margin: 0;
  1314. }
  1315. .report-export-action-btn+.report-export-action-btn {
  1316. margin-left: 12rpx;
  1317. }
  1318. .report-export-action-btn.report-export-primary {
  1319. background: #2c69ff;
  1320. color: #fff;
  1321. }
  1322. .report-export-action-btn.report-export-info {
  1323. background: #67c23a;
  1324. color: #fff;
  1325. }
  1326. .report-export-loading-row {
  1327. justify-content: center;
  1328. }
  1329. .report-export-loading-wrapper {
  1330. width: 100%;
  1331. height: 76rpx;
  1332. display: flex;
  1333. align-items: center;
  1334. justify-content: center;
  1335. }
  1336. .report-export-loading-icon {
  1337. width: 40rpx;
  1338. height: 40rpx;
  1339. animation: spin 1s linear infinite;
  1340. }
  1341. @keyframes spin {
  1342. from {
  1343. transform: rotate(0deg);
  1344. }
  1345. to {
  1346. transform: rotate(360deg);
  1347. }
  1348. }
  1349. .report-export-footer {
  1350. position: fixed;
  1351. left: 0;
  1352. right: 0;
  1353. bottom: 0;
  1354. padding: 12rpx 30rpx calc(50rpx + env(safe-area-inset-bottom));
  1355. background: #fff;
  1356. }
  1357. .report-export-footer-btn {
  1358. height: 86rpx;
  1359. border-radius: 999rpx;
  1360. background: #2c69ff;
  1361. color: #fff;
  1362. display: flex;
  1363. align-items: center;
  1364. justify-content: center;
  1365. font-size: 30rpx;
  1366. box-shadow: 0 8rpx 24rpx rgba(44, 105, 255, 0.35);
  1367. }
  1368. .report-export-create-modal-mask {
  1369. position: fixed;
  1370. left: 0;
  1371. right: 0;
  1372. top: 0;
  1373. bottom: 0;
  1374. background: rgba(0, 0, 0, 0.35);
  1375. z-index: 99;
  1376. }
  1377. .report-export-create-modal {
  1378. position: fixed;
  1379. left: 0;
  1380. right: 0;
  1381. bottom: 0;
  1382. width: 100%;
  1383. background: #fff;
  1384. border-top-left-radius: 45rpx;
  1385. border-top-right-radius: 45rpx;
  1386. z-index: 100;
  1387. box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.12);
  1388. transform: translateY(100%);
  1389. transition: transform 0.25s ease-out;
  1390. }
  1391. .report-export-create-modal--open {
  1392. transform: translateY(0) !important;
  1393. }
  1394. .report-export-create-modal-title {
  1395. position: relative;
  1396. padding: 28rpx 28rpx 12rpx;
  1397. font-size: 34rpx;
  1398. color: #333;
  1399. text-align: center;
  1400. line-height: 60rpx;
  1401. font-weight: 500;
  1402. }
  1403. .report-export-create-modal-close {
  1404. position: absolute;
  1405. right: 32rpx;
  1406. top: 50%;
  1407. transform: translateY(-50%);
  1408. padding: 10rpx;
  1409. color: #909399;
  1410. font-size: 55rpx;
  1411. line-height: 1;
  1412. }
  1413. .report-export-create-modal-body {
  1414. padding: 0 32rpx 100rpx;
  1415. }
  1416. .report-export-create-modal-row {
  1417. display: flex;
  1418. flex-direction: column;
  1419. margin-top: 32rpx;
  1420. position: relative;
  1421. }
  1422. .report-export-create-modal-label {
  1423. width: auto;
  1424. font-size: 28rpx;
  1425. color: #333;
  1426. margin-bottom: 16rpx;
  1427. font-weight: 500;
  1428. }
  1429. .report-export-create-modal-inputwrap {
  1430. flex: 1;
  1431. position: relative;
  1432. border: 1rpx solid #dcdfe6;
  1433. border-radius: 12rpx;
  1434. display: flex;
  1435. align-items: center;
  1436. min-height: 80rpx;
  1437. padding: 0 24rpx;
  1438. background-color: #fff;
  1439. }
  1440. .report-export-create-modal-static {
  1441. position: relative;
  1442. flex: 1;
  1443. max-height: 115rpx;
  1444. font-size: 28rpx;
  1445. color: #606266;
  1446. line-height: 40rpx;
  1447. padding: 20rpx 0;
  1448. overflow-y: auto;
  1449. padding-right: 20rpx;
  1450. }
  1451. .report-export-create-modal-input {
  1452. flex: 1;
  1453. height: 80rpx;
  1454. font-size: 28rpx;
  1455. color: #606266;
  1456. }
  1457. /deep/.report-export-dropdown-other-customer-input {
  1458. color: #666;
  1459. }
  1460. /* .report-export-create-modal-select-arrow {
  1461. width: 18rpx;
  1462. height: 18rpx;
  1463. border: 5rpx solid #999;
  1464. border-top: none;
  1465. border-left: none;
  1466. transform: rotate(45deg);
  1467. margin: 0 8rpx 10rpx 12rpx;
  1468. }
  1469. .report-export-create-modal-select-arrow.disabled {
  1470. opacity: 0.4;
  1471. pointer-events: none;
  1472. } */
  1473. .report-export-create-modal-dropdown {
  1474. position: absolute;
  1475. left: 0;
  1476. right: 0;
  1477. background: #fff;
  1478. border: 1rpx solid #eef0f4;
  1479. border-radius: 12rpx;
  1480. box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
  1481. z-index: 6;
  1482. max-height: 510rpx;
  1483. overflow-y: auto;
  1484. -webkit-overflow-scrolling: touch;
  1485. }
  1486. .report-export-create-modal-dropdown-list {
  1487. max-height: 350rpx;
  1488. }
  1489. .report-export-dropdown-search-row {
  1490. padding: 10rpx;
  1491. }
  1492. .report-export-dropdown-search-input {
  1493. width: 100%;
  1494. height: 60rpx;
  1495. border: 1rpx solid #eaeef4;
  1496. border-radius: 8rpx;
  1497. box-sizing: border-box;
  1498. padding: 0 16rpx;
  1499. font-size: 28rpx;
  1500. }
  1501. .report-export-create-modal-dropdown-item {
  1502. padding: 16rpx 20rpx;
  1503. font-size: 28rpx;
  1504. color: #333;
  1505. }
  1506. .report-export-selected {
  1507. background: #f0f5ff;
  1508. }
  1509. .report-export-input-arrow {
  1510. width: 16rpx;
  1511. height: 16rpx;
  1512. border-right: 3rpx solid #c0c4cc;
  1513. border-bottom: 3rpx solid #c0c4cc;
  1514. transform: rotate(45deg);
  1515. margin-top: -6rpx;
  1516. }
  1517. .customer-chip {
  1518. display: inline-block;
  1519. position: relative;
  1520. line-height: 50rpx;
  1521. border: 1rpx solid #eaeef4;
  1522. border-radius: 8rpx;
  1523. padding: 0rpx 44rpx 0rpx 16rpx;
  1524. margin-right: 8rpx;
  1525. margin-bottom: 8rpx;
  1526. font-size: 22rpx;
  1527. color: #333;
  1528. }
  1529. .customer-chip-close {
  1530. position: absolute;
  1531. right: 6rpx;
  1532. top: 0;
  1533. color: #666;
  1534. font-size: 28rpx;
  1535. padding: 0 8rpx;
  1536. border-radius: 6rpx;
  1537. }
  1538. .customer-clear-all {
  1539. position: absolute;
  1540. right: 6rpx;
  1541. top: 50%;
  1542. transform: translateY(-50%);
  1543. line-height: 50rpx;
  1544. padding: 8rpx 10rpx;
  1545. font-size: 40rpx;
  1546. }
  1547. .report-export-create-modal-estimated {
  1548. font-size: 28rpx;
  1549. color: #666;
  1550. }
  1551. .report-export-create-modal-footer {
  1552. padding: 18rpx 28rpx calc(50rpx + env(safe-area-inset-bottom));
  1553. }
  1554. .report-export-create-modal-btn {
  1555. line-height: 90rpx;
  1556. border-radius: 20rpx;
  1557. background: #2c69ff;
  1558. color: #fff;
  1559. text-align: center;
  1560. font-size: 30rpx;
  1561. }
  1562. .report-export-create-email-modal {
  1563. transform: translateY(200%);
  1564. height: auto;
  1565. top: 30%;
  1566. bottom: auto;
  1567. border-radius: 16rpx;
  1568. width: 600rpx;
  1569. left: 75rpx;
  1570. }
  1571. .report-export-email-input-wrap {
  1572. display: flex;
  1573. align-items: center;
  1574. background: #f5f7fa;
  1575. border-radius: 8rpx;
  1576. padding: 0 20rpx;
  1577. height: 80rpx;
  1578. border: 1rpx solid transparent;
  1579. }
  1580. .report-export-input-error {
  1581. border-color: #ff4d4f;
  1582. }
  1583. .report-export-email-input {
  1584. flex: 1;
  1585. font-size: 28rpx;
  1586. color: #333;
  1587. height: 100%;
  1588. }
  1589. .report-export-email-suffix {
  1590. font-size: 28rpx;
  1591. color: #333;
  1592. margin-left: 10rpx;
  1593. }
  1594. .report-export-error-text {
  1595. font-size: 24rpx;
  1596. color: #ff4d4f;
  1597. margin-top: 10rpx;
  1598. display: block;
  1599. }
  1600. </style>