index.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('com-export-dialog');
  4. ?>
  5. <div id="app" class="diy-index" v-cloak ref="contain" v-loading="loading">
  6. <div class="nav">手动分红导入</div>
  7. <div class="header_box" style="flex: 1;">
  8. <el-alert
  9. style="padding: 16px;"
  10. title=""
  11. type="error">
  12. 特别注意:<br>
  13. ① 按模板要求填写分红信息,不可添加列数,每一项不可以有空格<br>
  14. ② 当金额,积分,佣金必须为纯数字,都是必填项,如果其中一项不需要进行分红,则填写0<br>
  15. ③ 导出失败记录 操作完成后,请在左侧的【下载】菜单进行下载查看。<br>
  16. ④ 默认关闭导入负数,如要导入负值请开启按钮。<br>
  17. </el-alert>
  18. <div ref="crad-header" class="add_temp_box flex flex-x-between flex-y-center" style="margin: 20px 0;">
  19. <div class="add_temp_left flex flex-y-center">
  20. <el-button type="primary" size="small" @click="dialogFormVisible=true">导入分红</el-button>
  21. </div>
  22. <div class="switch_minus">
  23. <el-text class="mx-1" type="danger" style="margin-right: 10px;color: red">是否导入负数</el-text>
  24. <el-switch
  25. v-model="is_allow_minus"
  26. active-text="是"
  27. :active-value="1"
  28. :inactive-value="0"
  29. inactive-text="否" @change="switchAllowMinusChange">
  30. </el-switch>
  31. </div>
  32. </div>
  33. <!-- 搜索开始 -->
  34. <el-form ref="searchInfo" :model="searchInfo" size="small">
  35. <el-row :gutter="24">
  36. <el-col :span="9">
  37. <el-form-item label="导入时间">
  38. <el-date-picker
  39. v-model="operate_time"
  40. type="datetimerange"
  41. range-separator="至"
  42. start-placeholder="开始日期"
  43. end-placeholder="结束日期"
  44. value-format="yyyy-MM-dd HH:mm:ss"
  45. @change="addTimeChange"
  46. :default-time="['00:00:00', '23:59:59']"
  47. >
  48. </el-date-picker>
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="5">
  52. <el-form-item label="状态">
  53. <el-select v-model="searchInfo.export_status" placeholder="请选择状态">
  54. <el-option v-for="item in export_status_arr" :label="item.name" :value="item.status" :key="item.status"></el-option>
  55. </el-select>
  56. </el-form-item>
  57. </el-col>
  58. <el-col :span="5">
  59. <el-form-item label="操作人">
  60. <el-input style="width: auto;" v-model="searchInfo.operator_name" placeholder="请输入操作人" clearable></el-input>
  61. </el-form-item>
  62. </el-col>
  63. <el-col :span="4">
  64. <el-button @click="search" size="small" type="primary">筛选</el-button>
  65. <el-button type="danger" size="small" @click="resetSearch" v-if="show_clear_search_btn">清除条件</el-button>
  66. </el-col>
  67. </el-row>
  68. </el-form>
  69. <!-- 搜索结束 -->
  70. <div style="flex: 1;margin-top:10px">
  71. <el-table :data="list">
  72. <el-table-column prop="id" label="ID" width="100"></el-table-column>
  73. <el-table-column prop="operator_name" label="操作人"></el-table-column>
  74. <el-table-column prop="export_count" label="导入订单数"></el-table-column>
  75. <el-table-column prop="export_success_count" label="导入成功"></el-table-column>
  76. <el-table-column label="导入失败">
  77. <template slot-scope="scope">
  78. {{ scope.row.export_fail_count }}
  79. </template>
  80. </el-table-column>
  81. <el-table-column prop="export_status" label="状态">
  82. <template slot-scope="scope">
  83. <el-tag v-if="scope.row.export_status == 0" type="danger">处理中</el-tag>
  84. <el-tag v-else type="success">处理完成</el-tag>
  85. </template>
  86. </el-table-column>
  87. <el-table-column prop="created_at" label="操作时间">
  88. <template slot-scope="scope">
  89. <div>{{ scope.row.created_at | dateTimeFormat('Y-m-d H:i')}}</div>
  90. </template>
  91. </el-table-column>
  92. <el-table-column label="操作">
  93. <template slot-scope="scope">
  94. <div v-if="scope.row.export_status == 0"><span>导入正在处理</span></div>
  95. <div v-else>
  96. <span v-if="scope.row.export_count != scope.row.export_success_count">
  97. <el-button type="text" @click="handle('error',scope.row)">查看失败原因</el-button>
  98. <span style="color: #DCDFE6">|</span>
  99. <el-button type="text" @click="handle('export',scope.row)">导出失败分红记录</el-button>
  100. </span>
  101. <span v-else>
  102. <el-button type="text" @click="handle('exportSuccess',scope.row)">导出成功分红记录</el-button>
  103. <span style="color: #DCDFE6">|</span>
  104. 导入成功
  105. </span>
  106. </div>
  107. </template>
  108. </el-table-column>
  109. </el-table>
  110. </div>
  111. <div style="text-align: right;margin: 20px 0;">
  112. <el-pagination @current-change="pagination" background layout="prev, pager, next" :page-count="pageCount"></el-pagination>
  113. </div>
  114. </div>
  115. <el-dialog @close="dialogColse" title="导入" :visible.sync="dialogFormVisible">
  116. <el-form :model="form" label-width="150px" :rules="FormRules" ref="form">
  117. <el-form-item label="导入模板">
  118. <div>
  119. <com-upload class="flex flex-y-center" v-loading="uploading" :disabled="uploading" :fields="upload_type" @start="handleStart" @success="handleSuccess" @complete="handleComplete" :max="1" accept=".csv" style="width: 40%;float: left;margin-right: 20px;">
  120. <el-input size="small" :disabled="true" v-model="attachments[0].name" class="input-with-select">
  121. <el-button slot="append">选择文件</el-button>
  122. </el-input>
  123. </com-upload>
  124. <el-button @click="$navigate({r:'hand-bouns/default/download-hand-bouns-template'})" type="text">下载导入模板</el-button>
  125. </div>
  126. </el-form-item>
  127. <div class="tips-text" style="margin-left: 150px;">注:最大支持50000条数据(仅支持csv格式的文件)</div>
  128. </el-form>
  129. <div slot="footer">
  130. <el-button size="small" @click="dialogFormVisible = false">取 消</el-button>
  131. <el-button size="small" type="primary" @click="handle('submit',form)" :loading="butLoading">提 交</el-button>
  132. </div>
  133. </el-dialog>
  134. <!-- 错误列表 -->
  135. <el-dialog title="错误原因" :visible.sync="dialogErrorVisible">
  136. <el-table :data="listError">
  137. <el-table-column prop="id" label="ID" width="100"></el-table-column>
  138. <el-table-column prop="mobile" label="手机号码"></el-table-column>
  139. <el-table-column prop="balance" label="余额"></el-table-column>
  140. <el-table-column prop="score" label="积分"></el-table-column>
  141. <el-table-column prop="commission" label="佣金"></el-table-column>
  142. <el-table-column prop="reason" label="错误原因"></el-table-column>
  143. </el-table>
  144. <div style="text-align: right;margin: 20px 0;">
  145. <el-pagination @current-change="paginationError" background layout="prev, pager, next" :page-count="pageCountError"></el-pagination>
  146. </div>
  147. </el-dialog>
  148. </div>
  149. <script>
  150. new Vue({
  151. el: '#app',
  152. data() {
  153. return {
  154. loading: false,
  155. loadingError: false,
  156. uploading: false,
  157. dialogFormVisible: false,
  158. dialogErrorVisible: false,
  159. butLoading:false,
  160. list: [],
  161. listError: [],
  162. is_allow_minus: 0,
  163. export_id: 0,
  164. upload_type: {upload_type:'files'},
  165. express_companys: [],
  166. export_status_arr: [
  167. {name: '处理中', status: 0},
  168. {name: '已完成', status: 1},
  169. ],
  170. operate_time: null,
  171. searchInfo: {
  172. export_status: null,
  173. operator_name: null,
  174. start_time: null,
  175. end_time: null,
  176. },
  177. page: 1,
  178. pageCount: 0,
  179. pageError: 1,
  180. pageCountError: 0,
  181. attachments: [{name: ''}],
  182. form: {
  183. bouns_file: null,
  184. },
  185. FormRules: {
  186. bouns_file: [
  187. { required: true, message: '模板不能为空', trigger: 'blur' },
  188. ],
  189. },
  190. }
  191. },
  192. created() {
  193. this.getList();
  194. //this.getOrderShipping();
  195. },
  196. computed: {
  197. show_clear_search_btn: function() {
  198. return !isEmpty(this.searchInfo.export_status) ||
  199. !isEmpty(this.searchInfo.operator_name) ||
  200. !isEmpty(this.searchInfo.start_time) ||
  201. !isEmpty(this.searchInfo.end_time);
  202. }
  203. },
  204. methods: {
  205. handleStart(files) {
  206. this.uploading = true;
  207. },
  208. switchAllowMinusChange(val) {
  209. let message = "关闭";
  210. if (val === 1) message = "开启";
  211. this.$confirm("您确定要" + message + "可导入负数吗?", '提示', {
  212. type: 'warning'
  213. }).then(() => {
  214. request({
  215. params: {
  216. r: 'hand-bouns/default/allow-minus'
  217. },
  218. method: 'post',
  219. data: {is_allow_minus: val},
  220. }).then(e => {
  221. if (e.data.code === 0) {
  222. this.$message.success(e.data.msg);
  223. } else {
  224. this.$message.error(e.data.msg);
  225. }
  226. })
  227. }).catch(() => {
  228. this.is_allow_minus = this.is_allow_minus === 1 ? 0 : 1;
  229. })
  230. },
  231. handleSuccess(file) {
  232. if (file.response && file.response.data && file.response.data.code === 0) {
  233. const newItem = {
  234. url: file.response.data.data.url,
  235. name: file.response.data.data.name,
  236. };
  237. this.attachments.unshift(newItem);
  238. }
  239. },
  240. handleComplete(files) {
  241. this.form.bouns_file = this.attachments[0].url;
  242. this.uploading = false;
  243. },
  244. handleExpressChange(e){
  245. let index = this.express_companys.findIndex(v => v.id == e);
  246. this.form.express_id = this.express_companys[index].id;
  247. this.form.express_name = this.express_companys[index].name;
  248. },
  249. getOrderShipping(){
  250. request({
  251. params: {
  252. r: 'mall/order/shipping'
  253. },
  254. }).then(res => {
  255. if(res.data.code == 0){
  256. this.express_companys = res.data.data.express_list
  257. this.form.customer_name = res.data.data.jd_mch_code
  258. }
  259. })
  260. },
  261. // 弹框关闭事件回调
  262. dialogColse() {
  263. this.form = {
  264. express_id: null,
  265. express_name: null,
  266. bouns_file: null,
  267. };
  268. },
  269. search() {
  270. this.getList(this.searchInfo);
  271. },
  272. resetSearch() {
  273. this.searchInfo = {
  274. status: null,
  275. operator_name: null,
  276. start_time: null,
  277. end_time: null,
  278. };
  279. this.page = 1;
  280. this.getList();
  281. },
  282. addTimeChange(v){
  283. this.searchInfo.start_time = v?v[0]:'';
  284. this.searchInfo.end_time = v?v[1]:'';
  285. },
  286. pagination(currentPage) {
  287. let self = this;
  288. self.page = currentPage;
  289. self.getList();
  290. },
  291. paginationError(currentPage) {
  292. let self = this;
  293. self.pageError = currentPage;
  294. self.getListError();
  295. },
  296. handle(type, data = null) {
  297. let id = data ? parseInt(data.id) : '';
  298. switch (type) {
  299. case 'submit':
  300. this.butLoading = true;
  301. this.send(data, 'hand-bouns/default/index',(resp) => {
  302. if (resp.code == 0) {
  303. this.dialogFormVisible = false;
  304. this.dialogColse();
  305. this.butLoading = false;
  306. }
  307. });
  308. break;
  309. case 'error':
  310. this.export_id = data.id;
  311. this.dialogErrorVisible = true;
  312. this.listError = [];
  313. this.pageCountError = 0;
  314. this.getListError()
  315. break;
  316. case 'export':
  317. var param = {export_id: data.id, flag: 'EXPORT'};
  318. this.send(param, 'hand-bouns/default/export-error');
  319. break;
  320. case 'exportSuccess':
  321. var param = {export_id: data.id, flag: 'EXPORT'};
  322. this.send(param, 'hand-bouns/default/export-success');
  323. break;
  324. }
  325. },
  326. send(params, url = '', callback) {
  327. let self = this;
  328. request({
  329. params: {
  330. r: url,
  331. },
  332. method: 'post',
  333. data: params
  334. }).then(e => {
  335. if (e.data.code == 0) {
  336. self.$message.success(e.data.msg);
  337. self.getList();
  338. } else {
  339. self.$message.error(e.data.msg);
  340. }
  341. if (callback) callback(e.data);
  342. }).catch(e => {
  343. console.log(e);
  344. });
  345. },
  346. getList($search = null) {
  347. this.loading = true;
  348. let basic_params = {
  349. r: 'hand-bouns/default/index',
  350. page: this.page,
  351. };
  352. var params = Object.assign(basic_params, $search);
  353. this.$request({
  354. params: params,
  355. method: 'get',
  356. }).then(e => {
  357. this.loading = false;
  358. if (e.data.code == 0) {
  359. this.list = e.data.data.list.list;
  360. this.is_allow_minus = e.data.data.is_allow_minus;
  361. this.pageCount = e.data.data.page_count;
  362. }
  363. });
  364. },
  365. getListError() {
  366. this.loadingError = true;
  367. this.$request({
  368. params: {
  369. r: 'hand-bouns/default/export-error',
  370. page: this.pageError,
  371. export_id: this.export_id,
  372. },
  373. method: 'get',
  374. }).then(e => {
  375. this.loading = false;
  376. if (e.data.code == 0) {
  377. this.listError = e.data.data.list;
  378. this.pageCountError = e.data.data.page_count;
  379. }
  380. });
  381. },
  382. }
  383. })
  384. </script>
  385. <style scoped>
  386. .nav {
  387. background: #ffffff;
  388. border-radius: 5px;
  389. padding: 26px 24px;
  390. margin-bottom: 10px;
  391. }
  392. .diy-index {
  393. display: flex;
  394. flex-direction: column;
  395. }
  396. .header_box {
  397. display: flex;
  398. flex-direction: column;
  399. padding: 25px;
  400. background: #fff;
  401. border-radius: 5px 5px 0 0;
  402. color: #808695;
  403. }
  404. .add_temp_right {
  405. width: 400px;
  406. }
  407. .operation {
  408. cursor: pointer;
  409. color: #409eff;
  410. }
  411. .operation:hover {
  412. color: #fb6638;
  413. }
  414. /* 公共样式 */
  415. .flex {
  416. display: -webkit-box;
  417. display: -webkit-flex;
  418. /* #ifndef APP-NVUE */
  419. display: flex;
  420. /* #endif */
  421. }
  422. .flex-x-center {
  423. display: -webkit-box;
  424. display: -webkit-flex;
  425. /* #ifndef APP-NVUE */
  426. display: flex;
  427. /* #endif */
  428. -webkit-box-pack: center;
  429. -webkit-justify-content: center;
  430. -ms-flex-pack: center;
  431. justify-content: center;
  432. }
  433. .flex-x-between {
  434. display: -webkit-box;
  435. display: -webkit-flex;
  436. /* #ifndef APP-NVUE */
  437. display: flex;
  438. /* #endif */
  439. -webkit-box-pack: space-between;
  440. -webkit-justify-content: space-between;
  441. -ms-flex-pack: space-between;
  442. justify-content: flex-start;
  443. }
  444. .switch_minus {
  445. margin-left: 20px;
  446. }
  447. .flex-y-center {
  448. display: -webkit-box;
  449. display: -webkit-flex;
  450. /* #ifndef APP-NVUE */
  451. display: flex;
  452. /* #endif */
  453. -webkit-box-align: center;
  454. -webkit-align-items: center;
  455. -ms-flex-align: center;
  456. -ms-grid-row-align: center;
  457. align-items: center;
  458. }
  459. /* 溢出隐藏 */
  460. .over1 {
  461. text-overflow: -o-ellipsis-lastline;
  462. overflow: hidden;
  463. text-overflow: ellipsis;
  464. display: -webkit-box;
  465. -webkit-line-clamp: 1;
  466. -webkit-box-orient: vertical;
  467. }
  468. .el-card {
  469. background: transparent;
  470. box-shadow: none !important;
  471. border: 0;
  472. }
  473. .el-card__body {
  474. padding: 0;
  475. }
  476. .el-table td,
  477. .el-table th {
  478. padding: 12px 0
  479. }
  480. </style>