index.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <template>
  2. <el-main>
  3. <el-card shadow="never">
  4. <template #header>
  5. <span>剪辑师申请审核</span>
  6. </template>
  7. <el-table v-loading="loading" :data="list">
  8. <el-table-column prop="id" label="ID" width="80" />
  9. <el-table-column prop="real_name" label="真实姓名" min-width="100" show-overflow-tooltip />
  10. <el-table-column prop="card" label="身份证" min-width="160" show-overflow-tooltip />
  11. <el-table-column prop="phone" label="手机号" width="130" />
  12. <el-table-column prop="wechat" label="微信号" min-width="120" show-overflow-tooltip />
  13. <el-table-column label="作品链接" min-width="160">
  14. <template #default="{ row }">
  15. <el-link v-if="row.works" :href="row.works" target="_blank" type="primary">打开</el-link>
  16. <span v-else>-</span>
  17. </template>
  18. </el-table-column>
  19. <el-table-column label="状态" width="100">
  20. <template #default="{ row }">
  21. <el-tag size="small" :type="applyStatusType(row.status)">
  22. {{ applyStatusText(row.status) }}
  23. </el-tag>
  24. </template>
  25. </el-table-column>
  26. <el-table-column prop="remark" label="审核备注" min-width="120" show-overflow-tooltip />
  27. <el-table-column label="申请时间" min-width="170">
  28. <template #default="{ row }">
  29. {{ formatDispTime(row.created_at) }}
  30. </template>
  31. </el-table-column>
  32. <el-table-column label="更新时间" min-width="170">
  33. <template #default="{ row }">
  34. {{ formatDispTime(row.updated_at) }}
  35. </template>
  36. </el-table-column>
  37. <el-table-column label="操作" width="200" fixed="right">
  38. <template #default="{ row }">
  39. <el-button
  40. v-if="isPending(row)"
  41. type="success"
  42. size="small"
  43. @click="openRemark(row, 'agree')"
  44. >
  45. 同意
  46. </el-button>
  47. <el-button
  48. v-if="isPending(row)"
  49. type="danger"
  50. size="small"
  51. plain
  52. @click="openRemark(row, 'refuse')"
  53. >
  54. 拒绝
  55. </el-button>
  56. <span v-if="!isPending(row)" class="muted">已处理</span>
  57. </template>
  58. </el-table-column>
  59. </el-table>
  60. <div class="pager">
  61. <el-pagination
  62. background
  63. layout="total, prev, pager, next, sizes"
  64. :total="total"
  65. :current-page="query.page"
  66. :page-size="query.limit"
  67. :page-sizes="[5, 10, 20, 50]"
  68. @current-change="handlePageChange"
  69. @size-change="handleSizeChange"
  70. />
  71. </div>
  72. </el-card>
  73. <el-dialog v-model="remarkDialog" :title="remarkTitle" width="420px" destroy-on-close @closed="resetRemark">
  74. <el-input v-model="remark" type="textarea" :rows="4" placeholder="请输入备注(必填)" maxlength="200" show-word-limit />
  75. <template #footer>
  76. <el-button @click="remarkDialog = false">取消</el-button>
  77. <el-button type="primary" :loading="submitting" @click="submitRemark">确定</el-button>
  78. </template>
  79. </el-dialog>
  80. </el-main>
  81. </template>
  82. <script>
  83. export default {
  84. name: "CutterApply",
  85. data() {
  86. return {
  87. loading: false,
  88. submitting: false,
  89. list: [],
  90. total: 0,
  91. query: { page: 1, limit: 10 },
  92. remarkDialog: false,
  93. remarkTitle: "",
  94. remark: "",
  95. remarkAction: "",
  96. currentRow: null
  97. };
  98. },
  99. created() {
  100. this.getList();
  101. },
  102. methods: {
  103. /** 后端为日期字符串 "2026-04-29 12:17:09" 或时间戳 */
  104. formatDispTime(val) {
  105. if (val === undefined || val === null || val === "") return "-";
  106. if (typeof val === "string" && /^\d{4}-\d{2}-\d{2}/.test(val.trim())) {
  107. return val.trim();
  108. }
  109. const num = Number(val);
  110. if (!Number.isFinite(num) || num <= 0) return String(val);
  111. const sec = num > 1e12 ? Math.floor(num / 1000) : num;
  112. return this.$TOOL.getTime(sec, "YYYY-MM-DD HH:mm:ss");
  113. },
  114. applyStatusText(status) {
  115. const n = Number(status);
  116. const map = { 0: "待审核", 1: "已通过", 2: "已拒绝" };
  117. return map[n] !== undefined ? map[n] : status === undefined || status === null ? "-" : String(status);
  118. },
  119. applyStatusType(status) {
  120. const n = Number(status);
  121. if (n === 1) return "success";
  122. if (n === 2) return "danger";
  123. return "warning";
  124. },
  125. isPending(row) {
  126. const s = row.status;
  127. return s === undefined || s === null || Number(s) === 0;
  128. },
  129. async getList() {
  130. this.loading = true;
  131. try {
  132. const res = await this.$API.cutter.applyList.get(this.query);
  133. if (res.code !== 1) {
  134. this.$message.error(res.msg || "获取申请列表失败");
  135. return;
  136. }
  137. const data = res.data || {};
  138. this.list = data.list || data.data || [];
  139. this.total = Number(data.count ?? data.total ?? this.list.length ?? 0);
  140. } finally {
  141. this.loading = false;
  142. }
  143. },
  144. handlePageChange(page) {
  145. this.query.page = page;
  146. this.getList();
  147. },
  148. handleSizeChange(limit) {
  149. this.query.limit = limit;
  150. this.query.page = 1;
  151. this.getList();
  152. },
  153. openRemark(row, action) {
  154. this.currentRow = row;
  155. this.remarkAction = action;
  156. this.remarkTitle = action === "agree" ? "同意申请" : "拒绝申请";
  157. this.remark = "";
  158. this.remarkDialog = true;
  159. },
  160. resetRemark() {
  161. this.currentRow = null;
  162. this.remarkAction = "";
  163. this.remark = "";
  164. },
  165. async submitRemark() {
  166. const text = (this.remark || "").trim();
  167. if (!text) {
  168. this.$message.warning("请填写备注");
  169. return;
  170. }
  171. if (!this.currentRow) return;
  172. this.submitting = true;
  173. try {
  174. const id = this.currentRow.id;
  175. const body = { remark: text };
  176. const res =
  177. this.remarkAction === "agree"
  178. ? await this.$API.cutter.applyAgreed.post(id, body)
  179. : await this.$API.cutter.applyRefuse.post(id, body);
  180. if (res.code !== 1) {
  181. this.$message.error(res.msg || "操作失败");
  182. return;
  183. }
  184. this.$message.success(res.msg || "操作成功");
  185. this.remarkDialog = false;
  186. this.getList();
  187. } finally {
  188. this.submitting = false;
  189. }
  190. }
  191. }
  192. };
  193. </script>
  194. <style scoped>
  195. .pager {
  196. margin-top: 16px;
  197. display: flex;
  198. justify-content: flex-end;
  199. }
  200. .muted {
  201. color: var(--el-text-color-secondary);
  202. font-size: 12px;
  203. }
  204. </style>