watchlogReportdept.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. <template>
  2. <div class="app-container">
  3. <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
  4. <!-- <el-radio-group v-model="queryParams.dimension" @change="handleDimensionChange">-->
  5. <!-- <el-radio-button label="user">用户维度</el-radio-button>-->
  6. <!-- <el-radio-button label="sales">销售维度</el-radio-button>-->
  7. <!-- <el-radio-button label="company">公司维度</el-radio-button>-->
  8. <!-- </el-radio-group>-->
  9. <!-- <el-form-item label="公司名" prop="companyId">-->
  10. <!-- <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"-->
  11. <!-- clearable size="small">-->
  12. <!-- <el-option-->
  13. <!-- v-for="item in companys"-->
  14. <!-- :key="item.companyId"-->
  15. <!-- :label="item.companyName"-->
  16. <!-- :value="item.companyId"-->
  17. <!-- />-->
  18. <!-- </el-select>-->
  19. <!-- </el-form-item>-->
  20. <el-form-item label="所属部门" prop="deptId">
  21. <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" />
  22. </el-form-item>
  23. <el-form-item label="项目" prop="project">
  24. <el-select filterable v-model="queryParams.project" placeholder="请选择项目"
  25. clearable size="small">
  26. <el-option
  27. v-for="item in projectList"
  28. :key="item.dictValue"
  29. :label="item.dictLabel"
  30. :value="item.dictValue"
  31. />
  32. </el-select>
  33. </el-form-item>
  34. <el-form-item label="训练营" prop="trainingCampId">
  35. <el-select filterable v-model="queryParams.trainingCampId" placeholder="请选择训练营"
  36. clearable size="small" @change="handleCampChange">
  37. <el-option
  38. v-for="item in camps"
  39. :key="item.dictValue"
  40. :label="item.dictLabel"
  41. :value="item.dictValue"
  42. />
  43. </el-select>
  44. </el-form-item>
  45. <el-form-item>
  46. <treeselect style="width: 220px" v-model="queryParams.periodId" :options="deptOptions"
  47. clearable :show-count="true" placeholder="请选择归属营期" value-consists-of="LEAF_PRIORITY"
  48. :normalizer="normalizer" />
  49. </el-form-item>
  50. <el-form-item>
  51. <el-form-item label="看课时间" prop="createTime">
  52. <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
  53. type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
  54. @change="xdChange"></el-date-picker>
  55. </el-form-item>
  56. <el-form-item label="下单时间" prop="orderTime">
  57. <el-date-picker v-model="orderTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
  58. type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
  59. @change="ydChange"></el-date-picker>
  60. </el-form-item>
  61. </el-form-item>
  62. <el-form-item label="会员ID" prop="userId">
  63. <el-input v-model="queryParams.userId" placeholder="请输入会员ID" clearable size="small" />
  64. </el-form-item>
  65. <el-form-item label="会员手机号" prop="userPhone">
  66. <el-input v-model="queryParams.userPhone" placeholder="请输入会员手机号" clearable size="small" />
  67. </el-form-item>
  68. <el-form-item label="会员昵称" prop="nickName">
  69. <el-input v-model="queryParams.nickName" placeholder="请输入会员昵称" clearable size="small" />
  70. </el-form-item>
  71. <el-form-item>
  72. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  73. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  74. </el-form-item>
  75. </el-form>
  76. <el-row :gutter="10" class="mb8">
  77. <el-col :span="1.5">
  78. <el-button
  79. type="warning"
  80. plain
  81. icon="el-icon-download"
  82. size="mini"
  83. :loading="exportLoading"
  84. @click="handleExport"
  85. >导出</el-button>
  86. </el-col>
  87. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  88. </el-row>
  89. <el-table v-loading="loading" border :data="packageList">
  90. <el-table-column label="所属销售部门" align="center" prop="salesDept"/>
  91. <el-table-column label="销售数" align="center" prop="salesCount" />
  92. <el-table-column label="会员数" align="center" prop="userCount" />
  93. <el-table-column label="当前会员上线数" align="center" prop="onlineUserCount" />
  94. <el-table-column label="所属销售公司" align="center" prop="salesCompany"/>
  95. <el-table-column label="训练营" align="center" prop="trainingCampName"/>
  96. <el-table-column label="营期" align="center" prop="periodName"/>
  97. <el-table-column label="课程小节" align="center" prop="videoTitle" />
  98. <el-table-column label="完课数" align="center" prop="finishedCount" />
  99. <el-table-column label="未完课" align="center" prop="unfinishedCount" />
  100. <el-table-column label="完课率" align="center" prop="completionRate" />
  101. <el-table-column label="未看数" align="center" prop="notWatchedCount" />
  102. <el-table-column label="未答题人数" align="center" prop="notAnsweredCount" />
  103. <el-table-column label="红包金额" align="center" prop="redPacketAmount" />
  104. <el-table-column label="历史疗法订单数" align="center" prop="historyOrderCount" />
  105. </el-table>
  106. <div class="total-summary">
  107. <span class="total-title">总计:</span>
  108. <span class="total-item">完课数: {{ calculatedTotalData.finishedCount }}</span>
  109. <span class="total-item">未完课: {{ calculatedTotalData.unfinishedCount }}</span>
  110. <span class="total-item">完课率: {{ calculatedTotalData.completionRate }}</span>
  111. <span class="total-item">未看数: {{ calculatedTotalData.notWatchedCount }}</span>
  112. <span class="total-item">未答题人数: {{ calculatedTotalData.notAnsweredCount }}</span>
  113. <span class="total-item">红包金额: {{ calculatedTotalData.redPacketAmount }}</span>
  114. <span class="total-item">历史疗法订单数: {{ calculatedTotalData.historyOrderCount }}</span>
  115. </div>
  116. <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
  117. @pagination="getList" />
  118. <!-- 添加或修改套餐包对话框 -->
  119. <!-- <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
  120. <el-form ref="form" :model="form" :rules="rules" label-width="110px">
  121. <el-form-item label="套餐包名称" prop="packageName">
  122. <el-input v-model="form.packageName" placeholder="请输入套餐包名称" />
  123. </el-form-item>
  124. <el-form-item label="排序号" prop="sort">
  125. <el-input-number v-model="form.sort" :min="0" label="排序号"></el-input-number>
  126. </el-form-item>
  127. <el-form-item label="状态">
  128. <el-radio-group v-model="form.status">
  129. <el-radio
  130. v-for="dict in statusOptions"
  131. :key="dict.dictValue"
  132. :label="parseInt(dict.dictValue)"
  133. >{{dict.dictLabel}}</el-radio>
  134. </el-radio-group>
  135. </el-form-item>
  136. <el-form-item label="价格配置" prop="priceJson">
  137. <el-table :data="priceJson" :cell-style="{ textAlign: 'center' }" :header-cell-style="{textAlign: 'center'}" >
  138. <el-table-column label="子套餐标题" prop="title" width="150px">
  139. <template slot-scope="scope">
  140. <el-input v-model="scope.row.title" ></el-input>
  141. </template>
  142. </el-table-column>
  143. <el-table-column label="签约时长/日" prop="duration" width="150px">
  144. <template slot-scope="scope">
  145. <el-input-number v-model="scope.row.duration" controls-position="right" :min="0" size="small"></el-input-number>
  146. </template>
  147. </el-table-column>
  148. <el-table-column label="价格/元" prop="price" width="150px">
  149. <template slot-scope="scope">
  150. <el-input-number v-model="scope.row.price" controls-position="right" :min="0" size="small"></el-input-number>
  151. </template>
  152. </el-table-column>
  153. <el-table-column label="状态" prop="status">
  154. <template slot-scope="scope">
  155. <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949" ></el-switch>
  156. </template>
  157. </el-table-column>
  158. <el-table-column label="操作">
  159. <template slot-scope="scope">
  160. <el-button @click="deleteRow(scope.$index)" size="mini" type="text" v-if="priceJson.length>1">删除</el-button>
  161. <el-button @click="addRow" size="mini" type="text" >新增</el-button>
  162. </template>
  163. </el-table-column>
  164. </el-table>
  165. </el-form-item>
  166. </el-form>
  167. <div slot="footer" class="dialog-footer">
  168. <el-button type="primary" @click="submitForm">确 定</el-button>
  169. <el-button @click="cancel">取 消</el-button>
  170. </div>
  171. </el-dialog> -->
  172. </div>
  173. </template>
  174. <script>
  175. import {
  176. listPackage,
  177. getPackage,
  178. delPackage,
  179. addPackage,
  180. updatePackage,
  181. exportPackage,
  182. userReport, watchLogReport, exportWatchLogReport
  183. } from "@/api/store/package";
  184. import { getAllFollowTempName } from "@/api/store/followTemp";
  185. import { allIcd } from "@/api/store/icd";
  186. import Editor from '@/components/Editor/wang.vue';
  187. import Material from '@/components/Material/index.vue';
  188. import Treeselect from "@riophae/vue-treeselect";
  189. import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  190. import { listStore,getCampList,getPeriodList} from "@/api/store/storeProduct";
  191. import { getAllCateList } from "@/api/store/packageCate";
  192. import { Loading } from 'element-ui';
  193. import {getCompanyList} from "@/api/company/company";
  194. import {selectDeptTree} from "@/api/company/companyDept";
  195. export default {
  196. name: "WatchlogReport",
  197. components: {Treeselect},
  198. watch: {
  199. imageArr: function (val) {
  200. this.form.imgUrl = val.join(',')
  201. },
  202. photoArr: function (val) {
  203. this.form.images = val.join(',')
  204. },
  205. // 监听公司选择变化,动态加载对应部门
  206. // 'queryParams.companyId': {
  207. // handler(newVal) {
  208. // this.queryParams.deptId = null; // 清空已选择的部门
  209. // const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
  210. // const companyId = newVal || userInfo.companyId;
  211. // if (companyId) {
  212. // this.getTreeselect(companyId); // 根据公司ID获取部门树
  213. // } else {
  214. // this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
  215. // }
  216. // }
  217. // }
  218. },
  219. data() {
  220. return {
  221. normalizer: function(node) {
  222. return {
  223. id: node.id || node.dictValue,
  224. label: node.label || node.dictLabel,
  225. children: node.children
  226. }
  227. },
  228. columnConfig: {
  229. user: [
  230. { prop: 'userId', label: '会员id', width: 120 },
  231. { prop: 'nickName', label: '用户昵称', width: 120 },
  232. { prop: 'salesName', label: '所属销售', width: 120 },
  233. { prop: 'salesDept', label: '所属销售部门', width: 120, condition: () => this.showDeptNameColumn },
  234. { prop: 'salesCompany', label: '所属销售公司', width: 120 },
  235. { prop: 'trainingCampName', label: '训练营', width: 150 },
  236. { prop: 'periodName', label: '营期', width: 150 },
  237. { prop: 'videoTitle', label: '小节名称', width: 100 },
  238. { prop: 'watchStatus', label: '看课状态', width: 100 },
  239. { prop: 'duration', label: '播放时长', width: 120 },
  240. { prop: 'courseTime', label: '看课时间', width: 100 },
  241. { prop: 'finishTime', label: '完课时间', width: 100 },
  242. { prop: 'answerStatus', label: '答题状态', width: 100 },
  243. { prop: 'redPacketAmount', label: '红包金额', width: 120 },
  244. { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
  245. ],
  246. sales: [
  247. { prop: 'salesName', label: '销售', width: 120 },
  248. { prop: 'userCount', label: '会员数', width: 120 },
  249. { prop: 'onlineUserCount', label: '当前线上会员数', width: 120 },
  250. { prop: 'salesDept', label: '所属销售部门', width: 100, sortable: true },
  251. { prop: 'salesCompany', label: '所属销售公司', width: 120, sortable: true },
  252. { prop: 'trainingCampName', label: '训练营', width: 100, sortable: true },
  253. { prop: 'periodName', label: '营期', width: 100, sortable: true },
  254. { prop: 'videoTitle', label: '课程小节', width: 100, sortable: true },
  255. { prop: 'finishedCount', label: '完课数', width: 100, sortable: true },
  256. { prop: 'unfinishedCount', label: '未完课', width: 120, sortable: true },
  257. { prop: 'completionRate', label: '完课率', width: 100, sortable: true },
  258. { prop: 'courseTime', label: '发课时间', width: 100, sortable: true },
  259. { prop: 'notWatchedCount', label: '未看数', width: 100, sortable: true },
  260. { prop: 'notAnsweredCount', label: '未答题人数', width: 100, sortable: true },
  261. { prop: 'redPacketAmount', label: '红包金额', width: 120 },
  262. { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
  263. ],
  264. company: [
  265. { prop: 'salesDept', label: '销售部门', width: 120 },
  266. { prop: 'salesCount', label: '销售数', width: 120 },
  267. { prop: 'userCount', label: '会员数', width: 120 },
  268. { prop: 'onlineUserCount', label: '当前会员上线数', width: 100, sortable: true },
  269. { prop: 'salesCompany', label: '所属销售公司', width: 100, sortable: true },
  270. { prop: 'trainingCampName', label: '训练营', width: 120, sortable: true },
  271. { prop: 'periodName', label: '营期', width: 100, sortable: true },
  272. { prop: 'videoTitle', label: '课程小节', width: 100, sortable: true },
  273. { prop: 'finishedCount', label: '完课数', width: 100, sortable: true },
  274. { prop: 'unfinishedCount', label: '未完课', width: 120, sortable: true },
  275. { prop: 'completionRate', label: '完课率', width: 100, sortable: true },
  276. { prop: 'courseTime', label: '发课时间', width: 100, sortable: true },
  277. { prop: 'notWatchedCount', label: '未看数', width: 100, sortable: true },
  278. { prop: 'notAnsweredCount', label: '未答题人数', width: 100, sortable: true },
  279. { prop: 'redPacketAmount', label: '红包金额', width: 120 },
  280. { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
  281. ]
  282. },
  283. showDeptNameColumn: false,
  284. projectList: [],
  285. companys: [],
  286. camps: [],
  287. deptOptions : [],
  288. deptTreeOptions: [],
  289. uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS",
  290. photoArr: [],
  291. productTypeOptions: [],
  292. storeId: null,
  293. storeOPtions: [],
  294. totalMoney: 0.00,
  295. drugOpen: false,
  296. checkList: ['1'],
  297. drugList: [],
  298. productJson: [],
  299. calculatedTotalData: {
  300. finishedCount: 0,
  301. unfinishedCount: 0,
  302. completionRate: 0,
  303. notWatchedCount: 0,
  304. notAnsweredCount: 0,
  305. redPacketAmount: 0,
  306. historyOrderCount: 0
  307. },
  308. describeJson: { usageMethod: "", forPeople: "", tabootPeople: "", use: "" },
  309. icdList: [],
  310. show: {
  311. open: false,
  312. },
  313. priceJson: [
  314. { title: "套餐1", duration: "0", price: "0", status: true },
  315. ],
  316. // 遮罩层
  317. loading: true,
  318. // 导出遮罩层
  319. exportLoading: false,
  320. // 选中数组
  321. ids: [],
  322. // 非单个禁用
  323. single: true,
  324. // 非多个禁用
  325. multiple: true,
  326. // 显示搜索条件
  327. showSearch: true,
  328. startTime : null,
  329. endTime : null,
  330. // 总条数
  331. total: 0,
  332. createTime: null,
  333. orderTime: null,
  334. // 套餐包表格数据
  335. packageList: [],
  336. // 弹出层标题
  337. title: "",
  338. // 是否显示弹出层
  339. open: false,
  340. // 状态字典
  341. tempOptions: [],
  342. statusOptions: [],
  343. payTypeOptions: [],
  344. orOptions: [],
  345. packageTypeOptions: [],
  346. diseaseTypeOptions: [],
  347. packageSubTypeOptions: [],
  348. solarTermOptions: [],
  349. // 查询参数
  350. queryParams: {
  351. pageNum: 1,
  352. pageSize: 10,
  353. packageName: null,
  354. sort: null,
  355. priceJson: null,
  356. status: null,
  357. isDel: null,
  358. companyId:null,
  359. project:null,
  360. trainingCampId:null,
  361. periodId:null,
  362. sTime: null,
  363. eTime: null,
  364. orderSTime: null,
  365. orderETime: null,
  366. deptId: null,
  367. dimension: 'company'
  368. },
  369. // 表单参数
  370. form: {},
  371. };
  372. },
  373. computed: {
  374. // // 计算属性:根据当前维度返回动态列
  375. // dynamicColumns() {
  376. // const dimension = this.queryParams.dimension || 'user';
  377. // return this.columnConfig[dimension] || this.columnConfig.user;
  378. // }
  379. },
  380. created() {
  381. console.log('公司id是否存在',this.$store.state.user.user)
  382. this.getTreeselect(this.$store.state.user.user.companyId);
  383. this.$nextTick(() => {
  384. console.log('handleDimensionChange 方法是否存在:', typeof this.handleDimensionChange);
  385. console.log('所有方法:', Object.keys(this));
  386. });
  387. // 在调用 getList 前确保 dimension 参数存在
  388. if (!this.queryParams.dimension) {
  389. this.queryParams.dimension = 'company';
  390. }
  391. getCampList().then(response => {
  392. this.camps = response.data.list
  393. if (this.camps != null && this.camps.length > 0) {
  394. this.companyId = this.camps[0].dictValue;
  395. }
  396. this.camps.push({companyId: "-1", companyName: "无"})
  397. });
  398. getCompanyList().then(response => {
  399. this.companys = response.data;
  400. if (this.companys != null && this.companys.length > 0) {
  401. this.companyId = this.companys[0].companyId;
  402. }
  403. this.companys.push({companyId: "-1", companyName: "无"})
  404. });
  405. this.getList();
  406. this.getDicts("sys_company_status").then(response => {
  407. this.statusOptions = response.data;
  408. });
  409. this.getDicts("sys_company_or").then(response => {
  410. this.isDelOptions = response.data;
  411. this.orOptions = response.data;
  412. });
  413. this.getDicts("sys_package_pay_type").then(response => {
  414. this.payTypeOptions = response.data;
  415. });
  416. this.getDicts("sys_product_type").then(response => {
  417. this.productTypeOptions = response.data;
  418. });
  419. this.getDicts("sys_package_type").then(response => {
  420. this.packageTypeOptions = response.data;
  421. });
  422. this.getDicts("sys_package_sub_type").then(response => {
  423. this.packageSubTypeOptions = response.data;
  424. });
  425. this.getDicts("sys_course_project").then(e => {
  426. this.projectList = e.data;
  427. })
  428. // this.getDicts("sys_prescribe_disease_type").then(response => {
  429. // this.diseaseTypeOptions = response.data;
  430. // });
  431. },
  432. methods: {
  433. handleDimensionChange: function(val) {
  434. console.log('维度切换到:', val);
  435. // 重置分页
  436. this.queryParams.pageNum = 1;
  437. // 重新获取数据
  438. this.getList();
  439. },
  440. calculateTotals() {
  441. // 重置总计数据
  442. this.calculatedTotalData = {
  443. finishedCount: 0,
  444. unfinishedCount: 0,
  445. completionRate: 0,
  446. notWatchedCount: 0,
  447. notAnsweredCount: 0,
  448. redPacketAmount: 0,
  449. historyOrderCount: 0
  450. };
  451. // 遍历当前页数据计算总和
  452. this.packageList.forEach(item => {
  453. this.calculatedTotalData.finishedCount += Number(item.finishedCount) || 0;
  454. this.calculatedTotalData.unfinishedCount += Number(item.unfinishedCount) || 0;
  455. this.calculatedTotalData.notWatchedCount += Number(item.notWatchedCount) || 0;
  456. this.calculatedTotalData.notAnsweredCount += Number(item.notAnsweredCount) || 0;
  457. this.calculatedTotalData.redPacketAmount += Number(item.redPacketAmount) || 0;
  458. this.calculatedTotalData.historyOrderCount += Number(item.historyOrderCount) || 0;
  459. });
  460. const totalCount = this.calculatedTotalData.finishedCount + this.calculatedTotalData.unfinishedCount;
  461. if (totalCount > 0) {
  462. this.calculatedTotalData.completionRate = (this.calculatedTotalData.finishedCount / totalCount * 100).toFixed(2) + '%';
  463. } else {
  464. this.calculatedTotalData.completionRate = '0%';
  465. }
  466. },
  467. getTreeselect(companyId) {
  468. const query = { companyId: companyId };
  469. selectDeptTree(query).then((response) => {
  470. this.deptTreeOptions = response.data;
  471. });
  472. },
  473. compute(){
  474. this.totalMoney=0;
  475. var that=this;
  476. this.drugList.forEach (function (value) {
  477. that.totalMoney += value.money;
  478. });
  479. that.totalMoney=that.totalMoney.toFixed(2);
  480. },
  481. // saveData(row) {
  482. // // 在这里可以进行数据保存操作,比如将数据提交到后端进行保存
  483. // console.log("保存数据", row);
  484. // },
  485. /** 查询套餐包列表 */
  486. getList() {
  487. this.loading = true;
  488. // 添加调试日志,确认参数
  489. console.log('请求参数:', this.queryParams);
  490. watchLogReport(this.queryParams).then(response => {
  491. this.packageList = response.rows;
  492. this.total = response.total;
  493. this.calculateTotals();
  494. this.loading = false;
  495. // 检查是否有数据且 deptName 字段有值,决定是否显示该列
  496. if (this.packageList && this.packageList.length > 0) {
  497. this.showDeptNameColumn = this.packageList.some(item => item.deptName);
  498. } else {
  499. this.showDeptNameColumn = false;
  500. }
  501. });
  502. },
  503. /** 训练营变更处理 */
  504. handleCampChange(val) {
  505. this.queryParams.trainingCampId = val;
  506. this.queryParams.periodId = null; // 清空已选择的营期
  507. if (val) {
  508. // 获取对应的营期数据
  509. this.getPeriodByCamp(val);
  510. } else {
  511. // 如果清空训练营,也清空营期选项
  512. this.deptOptions = [];
  513. }
  514. // 触发查询
  515. this.handleQuery();
  516. },
  517. /** 根据训练营获取营期数据 */
  518. getPeriodByCamp(campId) {
  519. const param = { campId: campId };
  520. getPeriodList(param).then((response) => {
  521. console.log('接口返回数据:', response);
  522. console.log('营期列表数据:', response.data.list);
  523. this.deptOptions = response.data.list || [];
  524. console.log('deptOptions 已赋值:', this.deptOptions);
  525. }).catch(error => {
  526. console.error('获取营期数据失败:', error);
  527. this.deptOptions = [];
  528. });
  529. },
  530. // 取消按钮
  531. cancel() {
  532. this.open = false;
  533. this.reset();
  534. },
  535. // 表单重置
  536. reset() {
  537. this.form = {
  538. packageId: null,
  539. packageName: null,
  540. sort: null,
  541. productJson: null,
  542. status: 0,
  543. createTime: null,
  544. orderTime: null,
  545. updateTime: null,
  546. isDel: null,
  547. payType: ["1"],
  548. isShow: "1",
  549. packageType: "1",
  550. num: null,
  551. price: null,
  552. sales: null,
  553. diseaseType: null,
  554. tags: null,
  555. packageSubType: "1",
  556. describeJson: null,
  557. productType: null,
  558. totalPrice: null,
  559. inquiryPrice: null,
  560. productPrice: null,
  561. cycle: null,
  562. duration: null,
  563. imgUrl: null,
  564. images: null,
  565. storeId: null,
  566. recipeType: null,
  567. counts: null,
  568. followNum: null,
  569. secondName: null,
  570. };
  571. this.photoArr = [];
  572. this.resetForm("form");
  573. },
  574. /** 搜索按钮操作 */
  575. handleQuery() {
  576. this.queryParams.pageNum = 1;
  577. this.getList();
  578. },
  579. /** 重置按钮操作 */
  580. resetQuery() {
  581. this.resetForm("queryForm");
  582. this.handleQuery();
  583. // 清空所有时间相关变量
  584. this.createTime = null;
  585. this.orderTime = null;
  586. this.startTime = null;
  587. this.endTime = null;
  588. this.queryParams.sTime = null;
  589. this.queryParams.eTime = null;
  590. this.queryParams.orderSTime= null;
  591. this.queryParams.orderETime= null;
  592. },
  593. handleExport() {
  594. const queryParams = this.queryParams;
  595. this.$confirm('是否确认导出看课统计(公司)数据项?', "警告", {
  596. confirmButtonText: "确定",
  597. cancelButtonText: "取消",
  598. type: "warning"
  599. }).then(() => {
  600. this.exportLoading = true;
  601. return exportWatchLogReport(queryParams);
  602. }).then(response => {
  603. this.download(response.msg);
  604. this.exportLoading = false;
  605. }).catch(() => {});
  606. },
  607. xdChange() {
  608. if (this.createTime != null) {
  609. this.queryParams.sTime = this.createTime[0];
  610. this.queryParams.eTime = this.createTime[1];
  611. } else {
  612. this.queryParams.sTime = null;
  613. this.queryParams.eTime = null;
  614. }
  615. },
  616. ydChange() {
  617. if (this.orderTime != null) {
  618. this.queryParams.orderSTime = this.orderTime[0];
  619. this.queryParams.orderETime = this.orderTime[1];
  620. } else {
  621. this.queryParams.orderSTime = null;
  622. this.queryParams.orderETime = null;
  623. }
  624. }
  625. }
  626. };
  627. </script>
  628. <style>
  629. .icon-button {
  630. border-radius: 0;
  631. }
  632. .avatar-uploader .el-upload {
  633. border: 1px dashed #d9d9d9;
  634. border-radius: 6px;
  635. cursor: pointer;
  636. position: relative;
  637. overflow: hidden;
  638. }
  639. .avatar-uploader .el-upload:hover {
  640. border-color: #409EFF;
  641. }
  642. .avatar-uploader-icon {
  643. font-size: 28px;
  644. color: #8c939d;
  645. width: 150px;
  646. height: 150px;
  647. line-height: 150px !important;
  648. text-align: center;
  649. }
  650. .total-summary {
  651. margin-top: 15px;
  652. padding: 15px 20px;
  653. background: linear-gradient(135deg, #f5f7fa 0%, #e4e7f4 100%);
  654. border: 1px solid #dcdfe6;
  655. border-radius: 4px;
  656. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  657. display: flex;
  658. flex-wrap: wrap;
  659. align-items: center;
  660. }
  661. .total-title {
  662. font-weight: bold;
  663. font-size: 16px;
  664. color: #303133;
  665. margin-right: 20px;
  666. flex-shrink: 0;
  667. }
  668. .total-item {
  669. margin-right: 25px;
  670. padding: 5px 10px;
  671. background: white;
  672. border-radius: 3px;
  673. box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  674. display: inline-block;
  675. margin-bottom: 5px;
  676. font-size: 13px;
  677. color: #606266;
  678. }
  679. .total-item::before {
  680. content: "";
  681. display: inline-block;
  682. width: 3px;
  683. height: 3px;
  684. background: #409eff;
  685. border-radius: 50%;
  686. margin-right: 5px;
  687. vertical-align: middle;
  688. }
  689. /* 响应式处理 */
  690. @media (max-width: 768px) {
  691. .total-summary {
  692. flex-direction: column;
  693. align-items: flex-start;
  694. }
  695. .total-title {
  696. margin-bottom: 10px;
  697. }
  698. .total-item {
  699. margin-right: 10px;
  700. margin-bottom: 8px;
  701. }
  702. }
  703. </style>