diff --git a/src/api/ab98/tag.ts b/src/api/ab98/tag.ts new file mode 100644 index 0000000..fcd5884 --- /dev/null +++ b/src/api/ab98/tag.ts @@ -0,0 +1,59 @@ +import { http } from "@/utils/http"; + +export interface Ab98UserTagDTO { + /** 标签ID */ + tagId?: number; + /** 关联用户ID */ + ab98UserId?: number; + /** 标签名称 */ + tagName?: string; + /** 创建时间 */ + createTime?: string; +} + +export interface Ab98UserTagQuery extends BasePageQuery { + /** 关联用户ID */ + ab98UserId?: number; + /** 标签名称 */ + tagName?: string; + /** 开始时间 */ + startTime?: string; + /** 结束时间 */ + endTime?: string; +} + +export interface AddAb98UserTagCommand { + /** 关联用户ID */ + ab98UserId: number; + /** 标签名称 */ + tagName: string; +} + +export interface UpdateAb98UserTagCommand extends AddAb98UserTagCommand { + /** 标签ID */ + tagId: number; +} + +export const getAb98UserTagListApi = (params: Ab98UserTagQuery) => { + return http.request>>("get", "/ab98/userTags", { params }); +}; + +export const addAb98UserTagApi = (data: AddAb98UserTagCommand) => { + return http.request>("post", "/ab98/userTags", { data }); +}; + +export const updateAb98UserTagApi = (id: number, data: UpdateAb98UserTagCommand) => { + return http.request>("put", `/ab98/userTags/${id}`, { data }); +}; + +export const deleteAb98UserTagApi = (ids: number[]) => { + return http.request>("delete", `/ab98/userTags/${ids.join(',')}`); +}; + +export const deleteAb98UserTagConfirmApi = (tagId: number) => { + return http.request>("delete", `/ab98/userTags/${tagId}`); +}; + +export const getAb98UserTagNamesApi = () => { + return http.request>("get", "/ab98/userTags/names"); +}; \ No newline at end of file diff --git a/src/api/ab98/user.ts b/src/api/ab98/user.ts index 668e1b1..5a6980d 100644 --- a/src/api/ab98/user.ts +++ b/src/api/ab98/user.ts @@ -61,6 +61,7 @@ export interface Ab98UserQuery extends BasePageQuery { tel?: string; /** 身份证号码 */ idnum?: string; + tagName?: string; } export interface AddAb98UserCommand { diff --git a/src/views/user/ab98/detail.vue b/src/views/user/ab98/detail.vue index abf0617..aa3b713 100644 --- a/src/views/user/ab98/detail.vue +++ b/src/views/user/ab98/detail.vue @@ -3,6 +3,9 @@ import { ref, onMounted, watch } from "vue"; import { useRoute } from "vue-router"; import { type Ab98UserDetailDTO, getAb98UserDetailApi } from "@/api/ab98/user"; import { getOrderListApi, type OrderDTO } from "@/api/shop/order"; +import { Ab98UserTagDTO, addAb98UserTagApi, deleteAb98UserTagConfirmApi, getAb98UserTagListApi } from "@/api/ab98/tag"; +import { ElMessage, ElMessageBox } from "element-plus"; +import { PureTableBar } from "@/components/RePureTableBar"; defineOptions({ name: "Ab98UserDetail" @@ -11,6 +14,12 @@ defineOptions({ const route = useRoute(); const userInfo = ref({}); const loading = ref(false); +const tags = ref([]); +const tagsLoading = ref(false); +const showAddTagDialog = ref(false); +const addTagForm = ref({ + tagName: '' +}); // 基础信息 const basicInfo = ref({ @@ -57,11 +66,64 @@ async function fetchUserDetail() { const userId = route.query.id; const { data } = await getAb98UserDetailApi(Number(userId)); userInfo.value = data; + await fetchUserTags(); } finally { loading.value = false; } } +async function fetchUserTags() { + try { + tagsLoading.value = true; + const { data } = await getAb98UserTagListApi({ + ab98UserId: userInfo.value.ab98UserId, + pageSize: 6, + pageNum: 1 + }); + tags.value = data.rows; + } finally { + tagsLoading.value = false; + } +} + +async function handleAddTag() { + try { + tagsLoading.value = true; + await addAb98UserTagApi({ + ab98UserId: userInfo.value.ab98UserId, + tagName: addTagForm.value.tagName + }); + showAddTagDialog.value = false; + addTagForm.value.tagName = ''; + await fetchUserTags(); + ElMessage.success('标签添加成功'); + } catch (error) { + ElMessage.error('标签添加失败'); + } finally { + tagsLoading.value = false; + } +} + +async function handleDeleteTag(tagId: number) { + try { + await ElMessageBox.confirm('确定要删除这个标签吗?', '提示', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }); + tagsLoading.value = true; + await deleteAb98UserTagConfirmApi(tagId); + await fetchUserTags(); + ElMessage.success('标签删除成功'); + } catch (error) { + if (error !== 'cancel') { + ElMessage.error('标签删除失败'); + } + } finally { + tagsLoading.value = false; + } +} + onMounted(() => { fetchUserDetail(); }); @@ -107,6 +169,17 @@ onMounted(() => { {{ basicInfo.lastLogin }} {{ basicInfo.loginCount }} {{ basicInfo.device }} + +
+
+ + {{ tag.tagName }} + +
+ 添加标签 +
+
@@ -170,6 +243,16 @@ onMounted(() => { + + + + + + + + @@ -217,6 +300,45 @@ onMounted(() => { margin-bottom: 0px; } + .tag-container { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + + .user-tags { + flex: 1; + display: flex; + flex-wrap: wrap; + gap: 8px; + } + + .el-button { + width: 80px; + margin-left: auto; + } + } + + .el-button { + margin-top: 5px; + background-color: #409eff; + color: white; + border: none; + border-radius: 4px; + padding: 8px 16px; + font-size: 14px; + transition: all 0.3s; + + &:hover { + background-color: #66b1ff; + box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3); + } + + &:active { + background-color: #3a8ee6; + } + } + .order-item { margin-bottom: 20px; padding: 10px; diff --git a/src/views/user/ab98/index.vue b/src/views/user/ab98/index.vue index deae4dc..3983cb9 100644 --- a/src/views/user/ab98/index.vue +++ b/src/views/user/ab98/index.vue @@ -10,6 +10,7 @@ import Refresh from "@iconify-icons/ep/refresh"; import View from "@iconify-icons/ep/view"; import { useRouter } from "vue-router"; import { useMultiTagsStoreHook } from "@/store/modules/multiTags"; +import { getAb98UserTagNamesApi } from "@/api/ab98/tag"; defineOptions({ name: "Ab98User" @@ -17,10 +18,12 @@ defineOptions({ const router = useRouter(); const formRef = ref(); +const tagOptions = ref([]); const searchFormParams = reactive({ name: undefined, tel: undefined, - idnum: undefined + idnum: undefined, + tagName: undefined }); const pageLoading = ref(false); @@ -78,6 +81,9 @@ const handleViewDetail = (row: Ab98UserDTO) => { onMounted(() => { getList(); + getAb98UserTagNamesApi().then(res => { + tagOptions.value = res.data; + }); }) @@ -95,6 +101,11 @@ onMounted(() => { + + + + + 搜索 diff --git a/src/views/welcome/index.vue b/src/views/welcome/index.vue index 72627c0..75d71d1 100644 --- a/src/views/welcome/index.vue +++ b/src/views/welcome/index.vue @@ -1,7 +1,7 @@