登录,个人中心,联系客服

This commit is contained in:
Jason
2022-09-08 16:28:56 +08:00
parent fca4c24a8e
commit 04fad4b18c
49 changed files with 600 additions and 247 deletions

11
admin/src/api/consumer.ts Normal file
View File

@@ -0,0 +1,11 @@
import request from '@/utils/request'
// 用户列表
export function getUserList(params: any) {
return request.get({ url: '/user/list', params })
}
// 用户详情
export function getUserDetail(params: any) {
return request.get({ url: '/user/detail', params })
}

View File

@@ -22,7 +22,7 @@
>
<del-wrap @close="deleteImg(index)">
<file-item
:uri="element"
:uri="excludeDomain ? getImageUrl(element) : element"
:file-size="size"
:type="type"
></file-item>
@@ -82,6 +82,7 @@ import Popup from '@/components/popup/index.vue'
import FileItem from './file.vue'
import Material from './index.vue'
import Preview from './preview.vue'
import useAppStore from '@/stores/modules/app'
export default defineComponent({
components: {
Popup,
@@ -128,6 +129,11 @@ export default defineComponent({
uploadClass: {
type: String,
default: ''
},
//选择的url排出域名
excludeDomain: {
type: Boolean,
default: false
}
},
@@ -142,6 +148,7 @@ export default defineComponent({
const isAdd = ref(true)
const currentIndex = ref(-1)
const { disabled, limit, modelValue } = toRefs(props)
const { getImageUrl } = useAppStore()
const tipsText = computed(() => {
switch (props.type) {
case 'image':
@@ -164,7 +171,9 @@ export default defineComponent({
return limit.value - fileList.value.length
})
const handleConfirm = () => {
const selectUri = select.value.map((item) => item.uri)
const selectUri = select.value.map((item) =>
props.excludeDomain ? item.path : item.uri
)
if (!isAdd.value) {
fileList.value.splice(currentIndex.value, 1, selectUri.shift())
} else {
@@ -234,7 +243,8 @@ export default defineComponent({
previewUrl,
showPreview,
handlePreview,
handleClose
handleClose,
getImageUrl
}
}
})

View File

@@ -19,3 +19,22 @@ export enum ScreenEnum {
XL = 1280,
'2XL' = 1536
}
// 客户端类型
export enum ClientEnum {
MP_WEIXIN = 1, // 微信-小程序
OA_WEIXIN = 2, // 微信-公众号
H5 = 3, // H5
PC = 4, // PC
IOS = 5, //苹果
ANDROID = 6 //安卓
}
export const ClientMap = {
[ClientEnum.MP_WEIXIN]: '微信小程序',
[ClientEnum.OA_WEIXIN]: '微信公众号',
[ClientEnum.H5]: '手机H5Z',
[ClientEnum.PC]: '电脑PC',
[ClientEnum.IOS]: '苹果APP',
[ClientEnum.ANDROID]: '安卓APP'
}

View File

@@ -18,6 +18,9 @@ const useAppStore = defineStore({
}
},
actions: {
getImageUrl(url: string) {
return url ? `${this.config.ossDomain}${url}` : ''
},
getConfig() {
return new Promise((resolve, reject) => {
getConfig()

View File

@@ -18,8 +18,12 @@
<el-input v-model="formData.title" placeholder="请输入文章标题" />
</div>
</el-form-item>
<el-form-item label="文章标题" prop="cid">
<el-select class="w-80" v-model="formData.cid">
<el-form-item label="文章栏目" prop="cid">
<el-select
class="w-80"
v-model="formData.cid"
placeholder="请选择文章栏目"
>
<el-option
v-for="item in optionsData.articleCate"
:key="item.id"
@@ -107,15 +111,8 @@ const formData = reactive({
const formRef = shallowRef<FormInstance>()
const rules = reactive({
['base.tableName']: [{ required: true, message: '请输入表名称', trigger: 'blur' }],
['base.tableComment']: [{ required: true, message: '请输入表描述', trigger: 'blur' }],
['base.entityName']: [{ required: true, message: '请输入实体类名称', trigger: 'blur' }],
['base.authorName']: [{ required: true, message: '请输入作者', trigger: 'blur' }],
['gen.moduleName']: [{ required: true, message: '请输入模块名', trigger: 'blur' }],
['gen.functionName']: [{ required: true, message: '请输入功能名称', trigger: 'blur' }],
['gen.treePrimary']: [{ required: true, message: '请选择树主键字段', trigger: 'blur' }],
['gen.treeParent']: [{ required: true, message: '请选择树父级字段', trigger: 'blur' }],
['gen.treeName']: [{ required: true, message: '请选择树名称字段', trigger: 'blur' }]
title: [{ required: true, message: '请输入文章标题', trigger: 'blur' }],
cid: [{ required: true, message: '请输入表描述', trigger: 'blur' }]
})
const getDetails = async () => {

View File

@@ -49,10 +49,10 @@
<el-table-column label="ID" prop="id" min-width="80" />
<el-table-column label="封面" min-width="100">
<template #default="{ row }">
<image-contain
<el-image
v-if="row.image"
:src="row.image"
:width="60"
height="45"
class="w-[60px] h-[45px]"
:preview-src-list="[row.image]"
/>
</template>

View File

@@ -1,73 +1,51 @@
<template>
<div class="article-edit">
<div>
<el-card class="!border-none" shadow="never">
<el-page-header content="用户详情" @back="$router.back()" />
</el-card>
<el-card class="mt-4 !border-none" header="基本资料" shadow="never">
<el-form
ref="formRef"
class="ls-form"
:model="formData"
label-width="120px"
:rules="rules"
>
<el-form ref="formRef" class="ls-form" :model="formData" label-width="120px">
<div class="bg-page py-5 pl-20 mb-10">
<div class="mb-3 text-tx-regular">用户头像</div>
<el-avatar :size="58" />
<el-avatar :src="formData.avatar" :size="58" />
</div>
<el-form-item label="用户编号:"> 20000440556 </el-form-item>
<el-form-item label="用户昵称:"> 热心市民小张 </el-form-item>
<el-form-item label="账号:"> fwewrwre90 </el-form-item>
<el-form-item label="真实姓名:"> 张三 </el-form-item>
<el-form-item label="性别:"> 未知 </el-form-item>
<el-form-item label="联系电话:"> 13800138000 </el-form-item>
<el-form-item label="注册来源:"> 微信小程序 </el-form-item>
<el-form-item label="注册时间:"> 2022-02-15 12:12:12 </el-form-item>
<el-form-item label="最近登录时间:"> 2022-02-18 12:12:12 </el-form-item>
<el-form-item label="用户编号:"> {{ formData.sn }} </el-form-item>
<el-form-item label="用户昵称:"> {{ formData.nickname }} </el-form-item>
<el-form-item label="账号:"> {{ formData.username }} </el-form-item>
<el-form-item label="真实姓名:"> {{ formData.realName || '-' }} </el-form-item>
<el-form-item label="性别:"> {{ formData.sex }} </el-form-item>
<el-form-item label="联系电话:"> {{ formData.mobile || '-' }} </el-form-item>
<el-form-item label="注册来源:"> {{ formData.channel }} </el-form-item>
<el-form-item label="注册时间:"> {{ formData.createTime }} </el-form-item>
<el-form-item label="最近登录时间:"> {{ formData.lastLoginTime }} </el-form-item>
</el-form>
</el-card>
<footer-btns>
<el-button type="primary" @click="handleSave">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { useDictOptions } from '@/hooks/useDictOptions'
import { articleCateAll, articleDetail, articleEdit } from '@/api/article'
import { getUserDetail } from '@/api/consumer'
const route = useRoute()
const router = useRouter()
const formData = reactive({
id: '',
title: '',
image: '',
cid: '',
intro: '',
author: '',
content: '',
visit: 0,
sort: 0,
isShow: ''
avatar: '',
channel: '',
createTime: '',
lastLoginIp: '',
lastLoginTime: '',
mobile: '',
nickname: '',
realName: 0,
sex: 0,
sn: '',
username: ''
})
const formRef = shallowRef<FormInstance>()
const rules = reactive({
['base.tableName']: [{ required: true, message: '请输入表名称', trigger: 'blur' }],
['base.tableComment']: [{ required: true, message: '请输入表描述', trigger: 'blur' }],
['base.entityName']: [{ required: true, message: '请输入实体类名称', trigger: 'blur' }],
['base.authorName']: [{ required: true, message: '请输入作者', trigger: 'blur' }],
['gen.moduleName']: [{ required: true, message: '请输入模块名', trigger: 'blur' }],
['gen.functionName']: [{ required: true, message: '请输入功能名称', trigger: 'blur' }],
['gen.treePrimary']: [{ required: true, message: '请选择树主键字段', trigger: 'blur' }],
['gen.treeParent']: [{ required: true, message: '请选择树父级字段', trigger: 'blur' }],
['gen.treeName']: [{ required: true, message: '请选择树名称字段', trigger: 'blur' }]
})
const getDetails = async () => {
const data = await articleDetail({
const data = await getUserDetail({
id: route.query.id
})
Object.keys(formData).forEach((key) => {
@@ -76,20 +54,5 @@ const getDetails = async () => {
})
}
const { optionsData } = useDictOptions<{
articleCate: any[]
}>({
articleCate: {
api: articleCateAll
}
})
const handleSave = async () => {
await formRef.value?.validate()
await articleEdit(formData)
feedback.msgSuccess('操作成功')
router.back()
}
getDetails()
</script>

View File

@@ -5,26 +5,24 @@
<el-form-item label="用户信息">
<el-input
class="w-56"
v-model="queryParams.title"
v-model="queryParams.keyword"
placeholder="用户编号/昵称/手机号码"
/>
</el-form-item>
<el-form-item label="注册时间">
<el-select class="w-56" v-model="queryParams.cid">
<el-option label="全部" value />
<el-option
v-for="item in optionsData.articleCate"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<daterange-picker
v-model:startTime="queryParams.startTime"
v-model:endTime="queryParams.endTime"
/>
</el-form-item>
<el-form-item label="注册来源">
<el-select class="w-56" v-model="queryParams.isShow">
<el-option label="全部" value />
<el-option label="显示" :value="1" />
<el-option label="隐藏" :value="0" />
<el-select class="w-56" v-model="queryParams.channel">
<el-option
v-for="(item, key) in ClientMap"
:key="key"
:label="item"
:value="key"
/>
</el-select>
</el-form-item>
<el-form-item>
@@ -35,33 +33,17 @@
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<el-table size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column label="用户编号" prop="id" min-width="80" />
<el-table-column label="用户编号" prop="sn" min-width="120" />
<el-table-column label="头像" min-width="100">
<template #default="{ row }">
<image-contain
:src="row.image"
:width="60"
height="45"
:preview-src-list="[row.image]"
/>
<el-avatar :src="row.image" :size="50" />
</template>
</el-table-column>
<el-table-column label="昵称" prop="category" min-width="100" />
<el-table-column label="账号" prop="author" min-width="120" />
<el-table-column label="手机号码" prop="visit" min-width="100" />
<el-table-column label="性别" min-width="100">
<template #default="{ row }">
<el-switch
v-perms="['article:cate:change']"
v-if="row.id != 1"
v-model="row.isShow"
:active-value="0"
:inactive-value="1"
@change="changeStatus(row.id)"
/>
</template>
</el-table-column>
<el-table-column label="注册来源" prop="sort" min-width="100" />
<el-table-column label="昵称" prop="nickname" min-width="100" />
<el-table-column label="账号" prop="username" min-width="120" />
<el-table-column label="手机号码" prop="mobile" min-width="100" />
<el-table-column label="性别" prop="sex" min-width="100" />
<el-table-column label="注册来源" prop="channel" min-width="100" />
<el-table-column label="注册时间" prop="createTime" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
@@ -87,46 +69,21 @@
</div>
</template>
<script lang="ts" setup>
import { articleLists, articleDelete, articleStatus, articleCateAll } from '@/api/article'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import { getRoutePath } from '@/router'
import { getUserList } from '@/api/consumer'
import { ClientMap } from '@/enums/appEnums'
const queryParams = reactive({
title: '',
cid: '',
isShow: ''
keyword: '',
channel: '',
startTime: '',
endTime: ''
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: articleLists,
fetchFun: getUserList,
params: queryParams
})
const { optionsData } = useDictOptions<{
articleCate: any[]
}>({
articleCate: {
api: articleCateAll
}
})
const changeStatus = async (id: number) => {
try {
await articleStatus({ id })
feedback.msgSuccess('修改成功')
getLists()
} catch (error) {
getLists()
}
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await articleDelete({ id })
feedback.msgSuccess('删除成功')
getLists()
}
getLists()
</script>

View File

@@ -8,7 +8,12 @@
@close="handleDelete(index)"
>
<div class="bg-fill-light flex items-center w-full p-4 mb-4">
<material-picker v-model="item.image" upload-class="bg-body" size="60px">
<material-picker
v-model="item.image"
upload-class="bg-body"
size="60px"
exclude-domain
>
<template #upload>
<div class="upload-btn w-[60px] h-[60px]">
<icon name="el-icon-Plus" :size="20" />

View File

@@ -9,7 +9,7 @@
</el-form-item>
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*400px</div>
<div class="form-tips">最多添加5张建议图片尺寸750px*240px</div>
<del-wrap
v-for="(item, index) in content.data"
:key="index"
@@ -17,7 +17,11 @@
class="max-w-[400px]"
>
<div class="bg-fill-light flex items-center w-full p-4 mt-4">
<material-picker v-model="item.image" upload-class="bg-body" />
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input v-model="item.name" placeholder="请输入名称" />

View File

@@ -1,11 +1,12 @@
<template>
<div class="banner">
<div class="banner-image">
<image-contain width="100%" height="200px" :src="getImage" fit="contain" />
<image-contain width="100%" height="170px" :src="getImageUrl(getImage)" fit="contain" />
</div>
</div>
</template>
<script lang="ts" setup>
import useAppStore from '@/stores/modules/app'
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
@@ -19,6 +20,7 @@ const props = defineProps({
default: () => ({})
}
})
const { getImageUrl } = useAppStore()
const getImage = computed(() => {
const { data } = props.content
if (Array.isArray(data)) {

View File

@@ -12,7 +12,7 @@
</el-form-item>
<el-form-item label="客服二维码">
<div>
<material-picker v-model="content.qrcode" />
<material-picker v-model="content.qrcode" exclude-domain />
<div class="form-tips">建议图片尺寸200*200像素图片格式jpgpngjpeg</div>
</div>
</el-form-item>

View File

@@ -1,6 +1,6 @@
<template>
<div class="customer-service">
<image-contain width="140px" height="140px" :src="content.qrcode" alt="" />
<image-contain width="140px" height="140px" :src="getImageUrl(content.qrcode)" alt="" />
<div class="text-[15px] mt-[7px] font-medium">{{ content.title }}</div>
<div class="text-[#666] mt-[20px]">服务时间{{ content.time }}</div>
<div class="text-[#666] mt-[7px]">客服电话{{ content.mobile }}</div>
@@ -12,6 +12,7 @@
</div>
</template>
<script lang="ts" setup>
import useAppStore from '@/stores/modules/app'
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
@@ -25,6 +26,7 @@ defineProps({
default: () => ({})
}
})
const { getImageUrl } = useAppStore()
</script>
<style lang="scss" scoped>

View File

@@ -19,7 +19,7 @@
:key="index"
class="flex items-center border-b border-[#e5e5e5] h-[50px] px-[12px]"
>
<image-contain width="24px" height="24px" :src="item.image" alt="" />
<image-contain width="24px" height="24px" :src="getImageUrl(item.image)" alt="" />
<div class="ml-[10px] flex-1">{{ item.name }}</div>
<div>
<icon name="el-icon-ArrowRight" />
@@ -29,6 +29,7 @@
</div>
</template>
<script lang="ts" setup>
import useAppStore from '@/stores/modules/app'
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
@@ -42,6 +43,7 @@ defineProps({
default: () => ({})
}
})
const { getImageUrl } = useAppStore()
</script>
<style lang="scss" scoped>

View File

@@ -6,13 +6,14 @@
:key="index"
class="flex flex-col items-center w-1/5 mb-[15px]"
>
<image-contain width="41px" height="41px" :src="item.image" alt="" />
<image-contain width="41px" height="41px" :src="getImageUrl(item.image)" alt="" />
<div class="mt-[7px]">{{ item.name }}</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import useAppStore from '@/stores/modules/app'
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
@@ -26,6 +27,7 @@ const props = defineProps({
default: () => ({})
}
})
const { getImageUrl } = useAppStore()
</script>
<style lang="scss" scoped>

View File

@@ -17,7 +17,11 @@
class="max-w-[400px]"
>
<div class="bg-fill-light flex items-center w-full p-4 mt-4">
<material-picker v-model="item.image" upload-class="bg-body" />
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input v-model="item.name" placeholder="请输入名称" />

View File

@@ -1,11 +1,12 @@
<template>
<div class="banner mx-[10px] mt-[10px]">
<div class="banner-image">
<image-contain width="100%" height="100px" :src="getImage" fit="contain" />
<image-contain width="100%" height="100px" :src="getImageUrl(getImage)" fit="contain" />
</div>
</div>
</template>
<script lang="ts" setup>
import useAppStore from '@/stores/modules/app'
import type { PropType } from 'vue'
import type options from './options'
type OptionsType = ReturnType<typeof options>
@@ -19,6 +20,7 @@ const props = defineProps({
default: () => ({})
}
})
const { getImageUrl } = useAppStore()
const getImage = computed(() => {
const { data } = props.content
if (Array.isArray(data)) {

View File

@@ -12,12 +12,5 @@
height: 115px;
background-position: bottom;
background-size: 100% auto;
.search-con {
height: 100%;
height: 36px;
border-radius: 36px;
background: #f4f4f4;
color: #999999;
}
}
</style>

View File

@@ -2,7 +2,7 @@
<template>
<div class="website-filing">
<el-card shadow="never" class="!border-none">
<div class="mb-5">底部版权设置</div>
<div class="mb-5">站点底部版权备案信息设置</div>
<el-form ref="form" class="ls-form" label-width="100px">
<del-wrap
v-for="(item, index) in formData"
@@ -12,10 +12,13 @@
@close="handleDelete(index)"
>
<div class="bg-fill-lighter py-4">
<el-form-item label="显示名称" prop="name">
<el-form-item label="显示内容" prop="name">
<div class="w-80">
<div>
<el-input v-model="item.name" placeholder="请输入名称" />
<el-input
v-model="item.name"
placeholder="请输入内容 例如 ICP备案号"
/>
</div>
</div>
</el-form-item>