index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <template>
  2. <div class="user-page">
  3. <div class="user-title">
  4. <div class="title-l">
  5. <el-icon size="24" class="user-icon" color="#000000"><UserFilled /></el-icon>
  6. <span class="user-name">用户管理</span>
  7. <span class="title-line"></span>
  8. <span class="title-info">共 {{ totalVal }} 个用户,更新日期于 {{ formattedStartDate }}</span>
  9. </div>
  10. <div class="title-r">
  11. <el-input
  12. size="large"
  13. v-model="searchVal"
  14. @change="handleChangeGruop"
  15. style="width: 200px"
  16. placeholder="搜索用户/手机号"
  17. :prefix-icon="Search"
  18. />
  19. <el-button class="ml-10" size="large" type="primary" plain @click="downloadTemplate"
  20. >下载模板</el-button
  21. >
  22. <!-- <el-button size="large" type="primary" @click="uploadData">上传订单</el-button> -->
  23. <el-upload
  24. v-model:file-list="fileList"
  25. class="upload-demo"
  26. :action="config.base_url + 'adm/import_lighten_card_offline'"
  27. multiple
  28. :data="{ farmId: currentFarmId }"
  29. :headers="uploadHeaders"
  30. :on-success="handleUploadMsg"
  31. :on-error="handleUploadMsg"
  32. :limit="1"
  33. >
  34. <el-button class="ml-10" size="large" type="primary">上传订单</el-button>
  35. </el-upload>
  36. <el-button class="ml-10" size="large" type="primary" plain @click="openGroupPopup">新建分组</el-button>
  37. <!-- <el-button size="large" type="primary" plain>批量发送</el-button> -->
  38. </div>
  39. </div>
  40. <div class="user-btn-group">
  41. <div class="btn-l">
  42. <el-button size="large" type="primary">优质用户</el-button>
  43. <el-button size="large" type="primary" plain>中等用户</el-button>
  44. <el-button size="large" type="primary" plain>普通用户</el-button>
  45. </div>
  46. <div class="select-group">
  47. <!-- <el-select v-model="cityVal" placeholder="选择省份" size="large" class="ml-10" style="width: 100px">
  48. <el-option v-for="item in cityOptions" :key="item.value" :label="item.label" :value="item.value" />
  49. </el-select> -->
  50. <el-select v-model="groupVal" @change="handleChangeGruop" placeholder="选择分组" size="large" class="ml-10" style="width: 120px">
  51. <el-option label="全部分组" value="-2" />
  52. <el-option v-for="(item, index) in groupOptions" :key="index" :label="item.groupName" :value="item.id" />
  53. </el-select>
  54. <el-select v-model="levelVal" @change="handleChangeGruop" placeholder="守护等级" size="large" class="ml-10" style="width: 120px">
  55. <el-option label="全部等级" value="-2" />
  56. <el-option v-for="(item, index) in levelOptions" :key="index" :label="item.name" :value="item.id" />
  57. </el-select>
  58. </div>
  59. </div>
  60. <div class="table-wrap">
  61. <el-table :data="tableData" style="width: 100%" @selection-change="handleTableSelect" height="100%">
  62. <el-table-column type="selection" width="55" />
  63. <el-table-column property="miniUserId" label="用户编码" width="120" />
  64. <el-table-column property="name" label="用户昵称">
  65. <template #default="scope">
  66. <div class="user-info">
  67. <!-- <el-avatar :size="24" src="https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/91754/1750583672619.png" /> -->
  68. <el-avatar
  69. :size="24"
  70. :src="
  71. scope.row.icon || 'https://birdseye-img.sysuimars.com/dinggou-mini/defalut-icon.png'
  72. "
  73. />
  74. <span class="ml-10">{{ scope.row.name }}</span>
  75. </div>
  76. </template>
  77. </el-table-column>
  78. <el-table-column property="tel" label="联系电话" width="120" />
  79. <el-table-column property="address" label="具体住址" width="240" show-overflow-tooltip />
  80. <el-table-column label="守护等级">
  81. <template #default="scope">
  82. <span :class="['level-tag', 'level-' + scope.row.level?.id]">{{
  83. levelObj[scope.row.level?.id]
  84. }}</span>
  85. </template>
  86. </el-table-column>
  87. <el-table-column property="fosterCode" label="守护树编号">
  88. <template #default="scope">
  89. <span v-if="scope.row.fosterCode">{{ scope.row.fosterCode }}</span>
  90. <span v-else @click="toHomeBatch" class="wait-text">待分配</span>
  91. </template>
  92. </el-table-column>
  93. <el-table-column label="状态">
  94. <template #default="scope">
  95. <span :class="['status-text']">{{ scope.row.fosterStatus }}</span>
  96. </template>
  97. </el-table-column>
  98. <!-- <el-table-column label="日期" sortable>
  99. <template #default="scope">{{ scope.row.fosterDate }}</template>
  100. </el-table-column> -->
  101. <el-table-column property="groupName" label="分组" />
  102. <el-table-column label="操作" width="310">
  103. <template #default="scope">
  104. <div class="action-btn">
  105. <!-- <el-button type="primary" @click="handleMsg(scope.row)"
  106. ><el-icon class="el-icon--right"><Comment /></el-icon>发消息</el-button
  107. >
  108. <el-button type="primary" @click="handleMsg(scope.row)"
  109. ><el-icon><Briefcase /></el-icon>发礼物</el-button
  110. > -->
  111. <el-button type="warning" @click="clearUser(scope.row)"
  112. ><el-icon><DeleteFilled /></el-icon>清理</el-button
  113. >
  114. <el-button type="danger" @click="deleteUser(scope.row)"
  115. ><el-icon><Delete /></el-icon>删除</el-button
  116. >
  117. </div>
  118. </template>
  119. </el-table-column>
  120. </el-table>
  121. </div>
  122. <div class="pagination-wrap">
  123. <el-pagination
  124. v-model:current-page="currentPage"
  125. v-model:page-size="pageSize"
  126. :page-sizes="[10, 20, 50, 100]"
  127. layout="total, sizes, prev, pager, next"
  128. :total="totalVal"
  129. @size-change="handleSizeChange"
  130. @current-change="getTableData"
  131. />
  132. </div>
  133. <div class="put-btn" v-if="selectedRows.length">
  134. <div class="btn-r" @click="batchGroup">分配分组</div>
  135. <!-- <div class="btn-l ml-30">推送消息</div>
  136. <div class="btn-line"></div>
  137. <div class="btn-r">推送优惠券</div> -->
  138. </div>
  139. </div>
  140. <add-group ref="addGroupRef" @updateTableList="getTableData" @updateGroupList="getGroupList"></add-group>
  141. </template>
  142. <script setup>
  143. import { onMounted, ref } from "vue";
  144. import { Search } from "@element-plus/icons-vue";
  145. import config from "@/api/config.js";
  146. import { useStore } from "vuex";
  147. import { ElMessage, ElMessageBox } from "element-plus";
  148. import addGroup from "@/components/addGroup.vue";
  149. let store = useStore();
  150. import { useRouter } from "vue-router";
  151. import { dateFormat } from "@/utils/date_util";
  152. const router = useRouter();
  153. const currentFarmId = store.getters.userinfo.curFarmId
  154. const searchVal = ref(null);
  155. const levelObj = {
  156. 0: "平民",
  157. 1: "青铜守护",
  158. 2: "白银守护",
  159. 3: "赤金守护",
  160. 4: "星勋守护",
  161. };
  162. const tableData = ref([]);
  163. const selectedRows = ref([]);
  164. function handleTableSelect(selection) {
  165. selectedRows.value = selection;
  166. }
  167. const groupVal = ref('-2');
  168. const groupOptions = ref([]);
  169. const levelVal = ref('-2');
  170. const levelOptions = ref([]);
  171. const currentPage = ref(1);
  172. const pageSize = ref(20); // 每页显示20条数据
  173. const totalVal = ref(0);
  174. const startDate = new Date();
  175. // 格式化日期
  176. const formattedStartDate = dateFormat(startDate, "YY.mm.dd");
  177. onMounted(() => {
  178. getTableData();
  179. getGroupList();
  180. VE_API.manage_user
  181. .fetchLevelList({farmId: currentFarmId})
  182. .then(({ data }) => {
  183. levelOptions.value = data
  184. });
  185. });
  186. function getGroupList() {
  187. VE_API.manage_user
  188. .fetchGroupList({farmId: currentFarmId})
  189. .then(({ data }) => {
  190. groupOptions.value = data
  191. });
  192. }
  193. function handleChangeGruop(val) {
  194. currentPage.value = 1; // 重置页码
  195. getTableData()
  196. // 这里可以添加根据选择的分组进行数据过滤或其他操作
  197. }
  198. function handleSizeChange(newSize) {
  199. pageSize.value = newSize;
  200. currentPage.value = 1; // 重置页码
  201. getTableData();
  202. }
  203. function getTableData() {
  204. // 获取数据
  205. VE_API.manage_interface
  206. .fetchUserList({ farmId: currentFarmId, word: searchVal.value, level: (levelVal.value !== '-2') ? levelVal.value : null, groupId: (groupVal.value !== '-2') ? groupVal.value : null, page: currentPage.value - 1, limit: pageSize.value })
  207. .then(({ data, count }) => {
  208. tableData.value = data;
  209. totalVal.value = count;
  210. });
  211. }
  212. // 下载模板
  213. function downloadTemplate() {
  214. VE_API.manage_user
  215. .downloadTemplate()
  216. .then((response) => {
  217. const blob = new Blob([response], {
  218. type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  219. });
  220. const link = document.createElement("a");
  221. link.href = window.URL.createObjectURL(blob);
  222. link.download = "用户数据模板.xlsx";
  223. link.click();
  224. })
  225. .catch((error) => {
  226. console.error("下载模板失败:", error);
  227. });
  228. }
  229. const fileList = ref([]);
  230. const uploadHeaders = {
  231. token: store.getters.token,
  232. };
  233. // 上传数据
  234. function handleUploadMsg(res) {
  235. ElMessage.success(res.msg);
  236. getTableData(); // 刷新表格数据
  237. }
  238. // 清理数据
  239. function clearUser(item) {
  240. ElMessageBox.confirm(`确认清理 ${item.name} 的绑定树和手机号码吗?`, "提示", {
  241. confirmButtonText: "确定",
  242. cancelButtonText: "取消",
  243. type: "warning",
  244. }).then(() => {
  245. VE_API.manage_user.cleanBind({ miniUserId: item.miniUserId }).then(({ code }) => {
  246. if (code === 0) {
  247. ElMessage.success("清理成功");
  248. getTableData(); // 刷新表格数据
  249. }
  250. });
  251. }).catch(() => {});
  252. }
  253. // 删除数据
  254. function deleteUser(item) {
  255. ElMessageBox.confirm(`确认删除 ${item.name} 的守护权限吗?`, "提示", {
  256. confirmButtonText: "确定",
  257. cancelButtonText: "取消",
  258. type: "warning",
  259. }).then(() => {
  260. VE_API.manage_user.deleteUser({ id: item.id }).then(({ code }) => {
  261. if (code === 0) {
  262. ElMessage.success("删除成功");
  263. getTableData(); // 刷新表格数据
  264. }
  265. });
  266. }).catch(() => {});
  267. }
  268. const addGroupRef = ref(null);
  269. // 新建分组
  270. function openGroupPopup() {
  271. addGroupRef.value.openClientPopup("add");
  272. }
  273. // 批量分配分组
  274. function batchGroup() {
  275. addGroupRef.value.openClientPopup("edit", selectedRows.value.map(item => item.tel));
  276. }
  277. // 去待分配
  278. function toHomeBatch() {
  279. router.push("/layout/home?acitveName=待分配")
  280. }
  281. </script>
  282. <style lang="scss" scoped>
  283. .user-page {
  284. padding: 41px 20px 0 20px;
  285. width: 100%;
  286. height: 100%;
  287. box-sizing: border-box;
  288. display: flex;
  289. flex-direction: column;
  290. .user-title {
  291. display: flex;
  292. align-items: center;
  293. justify-content: space-between;
  294. .title-l {
  295. display: flex;
  296. align-items: center;
  297. .user-name {
  298. font-family: "PangMenZhengDao";
  299. padding-left: 10px;
  300. font-size: 24px;
  301. color: #000000;
  302. }
  303. .title-line {
  304. display: inline-block;
  305. width: 1px;
  306. height: 12px;
  307. background: rgba(0, 0, 0, 0.5);
  308. margin: 0 15px;
  309. }
  310. .title-info {
  311. color: rgba(0, 0, 0, 0.5);
  312. font-size: 12px;
  313. }
  314. }
  315. .title-r {
  316. display: flex;
  317. align-items: center;
  318. ::v-deep {
  319. .el-upload-list {
  320. display: none;
  321. }
  322. }
  323. }
  324. }
  325. .ml-10 {
  326. margin-left: 10px;
  327. }
  328. .ml-30 {
  329. margin-left: 30px;
  330. }
  331. .user-btn-group {
  332. padding: 24px 0;
  333. display: flex;
  334. align-items: center;
  335. justify-content: space-between;
  336. }
  337. .table-wrap {
  338. flex: 1;
  339. height: calc(100% - 44px - 88px - 70px);
  340. .action-btn {
  341. display: flex;
  342. align-items: center;
  343. }
  344. .user-info {
  345. display: flex;
  346. align-items: center;
  347. }
  348. .level-tag {
  349. font-size: 16px;
  350. line-height: 30px;
  351. padding: 0 10px;
  352. border-radius: 4px;
  353. }
  354. .level-0 {
  355. color: #03b2d5;
  356. background: rgba(3, 178, 213, 0.2);
  357. }
  358. .level-1 {
  359. color: #d88c4a;
  360. background: rgba(200, 156, 117, 0.2);
  361. }
  362. .level-2 {
  363. color: #6293c1;
  364. background: rgba(115, 193, 255, 0.2);
  365. }
  366. .level-3 {
  367. color: #b18c0d;
  368. background: rgba(243, 191, 48, 0.2);
  369. }
  370. .level-4 {
  371. color: #bd6fe8;
  372. background: rgba(236, 125, 255, 0.2);
  373. }
  374. .status-text {
  375. color: #7d7d7d;
  376. }
  377. .status-1 {
  378. color: #ffaa00;
  379. }
  380. .status-2 {
  381. color: #2199f8;
  382. }
  383. .wait-text {
  384. cursor: pointer;
  385. color: #2199f8;
  386. text-decoration: underline;
  387. }
  388. }
  389. .pagination-wrap {
  390. padding: 16px 0;
  391. display: flex;
  392. justify-content: end;
  393. }
  394. .put-btn {
  395. display: flex;
  396. align-items: center;
  397. justify-content: center;
  398. position: absolute;
  399. left: 50%;
  400. transform: translateX(-50%);
  401. bottom: 10px;
  402. .btn-l {
  403. padding: 12px 44px;
  404. background: #f0ac37;
  405. border-radius: 4px;
  406. font-size: 16px;
  407. color: #fff;
  408. cursor: pointer;
  409. }
  410. .btn-r {
  411. margin-left: 30px;
  412. padding: 12px 36px;
  413. background: #2199f8;
  414. border-radius: 4px;
  415. font-size: 16px;
  416. color: #fff;
  417. cursor: pointer;
  418. }
  419. }
  420. }
  421. </style>