提交 8b52866e authored 作者: 王鹏飞's avatar 王鹏飞

updates

上级 191a2512
......@@ -27,18 +27,18 @@
"devDependencies": {
"@rushstack/eslint-patch": "^1.1.3",
"@types/blueimp-md5": "^2.18.0",
"@types/node": "^17.0.25",
"@types/node": "^17.0.29",
"@types/qs": "^6.9.7",
"@vitejs/plugin-vue": "^2.3.1",
"@vue/eslint-config-typescript": "^10.0.0",
"@vue/tsconfig": "^0.1.3",
"ali-oss": "^6.17.1",
"chalk": "^5.0.1",
"eslint": "^8.13.0",
"eslint": "^8.14.0",
"eslint-plugin-vue": "^8.7.1",
"typescript": "~4.6.3",
"unplugin-auto-import": "^0.7.1",
"vite": "^2.9.5",
"vite": "^2.9.6",
"vite-plugin-checker": "^0.4.6",
"vue-tsc": "^0.34.10"
}
......
差异被折叠。
......@@ -29,3 +29,8 @@ export function uploadFile(data: Record<string, any>) {
})
.then(() => data)
}
// 删除评论
export function deleteComment(data: { id: string }) {
return httpRequest.post('/api/psp/backend/comment/delete', data)
}
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import { Delete } from '@element-plus/icons-vue'
import { deleteComment } from '@/api/base'
const props = defineProps<{ info: Record<string, any>; comments: { total: number; list: Record<string, any>[] } }>()
const emit = defineEmits(['remove'])
const imageList = computed<string[]>(() => {
try {
return JSON.parse(props.info.picture)
} catch (error) {
return []
}
})
const onRemove = (data: any) => {
ElMessageBox.confirm('确定要删除吗?', '提示').then(() => {
deleteComment({ id: data.id }).then(() => {
ElMessage({ type: 'success', message: '删除成功' })
emit('remove', data)
})
})
}
</script>
<template>
<div class="publish-item">
<div class="publish-item-hd" v-if="info.user_info">
<img
:src="info.user_info.avatar || 'https://webapp-pub.ezijing.com/weapp/share/default.jpg'"
class="publish-avatar"
/>
<div class="publish-item-hd-info">
<h5>{{ info.user_info.name }}</h5>
</div>
</div>
<div class="publish-item-bd">
<div class="publish-content" v-html="info.content || info.desc"></div>
<ul class="publish-picture">
<li v-for="url in imageList" :key="url">
<el-image :src="url" :preview-src-list="[url]" fit="cover" />
</li>
</ul>
<div class="publish-tools">
<p class="t1">{{ info.created_time }}</p>
</div>
<!-- 评论 -->
<div class="publish-comments" v-if="comments.total">
<div class="comment-item" v-for="item in comments.list" :key="item.id">
<div class="comment-item-hd">
<span>{{ item.user_name }}</span> <el-icon><delete @click="onRemove(item)" /></el-icon>
</div>
<div class="comment-item-bd">{{ item.content }}</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss">
.publish-item {
margin-bottom: 20px;
}
.publish-item-hd {
display: flex;
align-items: center;
}
.publish-item-hd-info {
flex: 1;
margin-left: 10px;
h5 {
font-size: 16px;
font-weight: 400;
color: #333333;
}
}
.publish-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
object-fit: cover;
}
.publish-item-bd {
margin-left: 60px;
}
.publish-content {
font-weight: 400;
line-height: 30px;
color: #333333;
}
.publish-picture {
margin-top: 10px;
display: flex;
li {
margin: 0 10px 10px 0;
width: 200px;
height: 200px;
border: 1px solid #e4e7ed;
border-radius: 10px;
overflow: hidden;
.el-image {
width: 100%;
height: 100%;
}
&:hover {
box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
}
}
}
.publish-tools {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: space-between;
color: #999;
.t2 {
display: flex;
align-items: center;
font-size: 14px;
cursor: pointer;
.el-icon {
margin-right: 5px;
}
}
}
.publish-comments {
margin: 10px 0;
padding: 10px 20px;
background-color: #f5f5f5;
border-radius: 10px;
}
.comment-item + .comment-item {
border-top: 1px solid #e4e7ed;
padding-top: 12px;
margin-top: 12px;
}
.comment-item {
&:hover {
.el-icon {
display: block;
}
}
}
.comment-item-hd {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 16px;
color: #033974;
.el-icon {
display: none;
cursor: pointer;
}
}
.comment-item-bd {
margin-top: 5px;
font-size: 14px;
color: #4e4e4e;
line-height: 20px;
}
.comment-more {
padding: 0.16rem 0;
font-size: 24px;
color: #033974;
line-height: 0.36rem;
text-align: center;
border-top: 0.01rem solid #d3d3d3;
cursor: pointer;
}
</style>
<script setup lang="ts">
import { withDefaults, ref, reactive, onMounted } from 'vue'
import { Search, RefreshLeft } from '@element-plus/icons-vue'
interface IRemoteProps {
......@@ -107,6 +106,7 @@ onMounted(() => {
defineExpose({ refetch })
</script>
<template>
<div class="table-list">
<div class="table-list-hd">
......@@ -120,21 +120,27 @@ defineExpose({ refetch })
</template>
<template v-else>
<!-- input -->
<el-input v-model="params[item.prop]" v-bind="item" clearable v-if="item.type === 'input'" />
<el-input
v-model="params[item.prop]"
v-bind="item"
clearable
@change="search"
v-if="item.type === 'input'"
/>
<!-- select -->
<el-select
v-model="params[item.prop]"
clearable
v-bind="item"
v-if="item.type === 'select'"
clearable
@change="search"
v-if="item.type === 'select'"
>
<template v-for="(option, index) in item.options" :key="index">
<el-option
:label="option[item.labelKey] || option.label"
:value="option[item.valueKey] || option.value"
></el-option>
</template>
<el-option
:label="option[item.labelKey] || option.label"
:value="option[item.valueKey] || option.value"
v-for="(option, index) in item.options"
:key="index"
/>
</el-select>
</template>
</el-form-item>
......@@ -153,7 +159,7 @@ defineExpose({ refetch })
<slot name="body" v-bind="{ data: dataList }">
<el-table :data="dataList" v-loading="loading" v-bind="$attrs" style="height: 100%" ref="tableRef">
<el-table-column v-bind="item" v-for="item in columns" :key="item.prop">
<template v-slot:default="scope" v-if="item.slots || item.computed">
<template #default="scope" v-if="item.slots || item.computed">
<slot :name="item.slots" v-bind="scope" v-if="item.slots"></slot>
<div v-html="item.computed(scope)" v-if="item.computed"></div>
</template>
......@@ -163,7 +169,7 @@ defineExpose({ refetch })
</div>
<!-- 底部 -->
<div class="table-list-ft">
<div style="padding: 10px 0">
<div>
<slot name="footer"></slot>
</div>
<el-pagination
......@@ -202,32 +208,15 @@ defineExpose({ refetch })
flex: 1;
}
.table-list-ft {
padding: 10px 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.table-list-pagination {
padding: 10px 0;
text-align: right;
}
.el-table-column--selection .cell {
padding: 0 14px !important;
}
.more-filter-drawer {
height: 100%;
display: flex;
flex-direction: column;
padding: 0 20px 20px;
box-sizing: border-box;
}
.more-filter {
flex: 1;
overflow-y: auto;
}
.more-filter-buttons {
display: flex;
.el-button {
flex: 1;
}
}
</style>
<script lang="ts">
export default {
name: 'AppAside'
}
</script>
<script setup lang="ts">
import { computed } from 'vue'
import type { Component } from 'vue'
import { useRoute } from 'vue-router'
import { User, Picture, Files, VideoCamera, Notebook, DishDot, QuestionFilled, Stamp } from '@element-plus/icons-vue'
const route = useRoute()
interface IMenuItem {
......
<script lang="ts">
export default { name: 'AppMain' }
</script>
<script setup lang="ts">
import AppBreadcrumb from './Breadcrumb.vue'
withDefaults(defineProps<{ hasBreadcrumb?: boolean }>(), {
hasBreadcrumb: true
})
</script>
<template>
<section class="app-main">
<div class="app-main-inner">
......@@ -11,15 +22,6 @@
</section>
</template>
<script>
import AppBreadcrumb from './Breadcrumb.vue'
export default {
name: 'AppMain',
props: { hasBreadcrumb: { type: Boolean, default: true } },
components: { AppBreadcrumb }
}
</script>
<style>
.app-main {
position: relative;
......
......@@ -7,7 +7,7 @@ export function getAuditList(params?: { type?: string; page?: number; page_size?
}
// 获取审核详情
export function getAudit(params: { id: string }) {
export function getAudit(params: { id: string; page_size?: number; page?: number }) {
return httpRequest.get('/api/psp/backend/auditing/view', { params })
}
......
......@@ -5,6 +5,9 @@ export const routes: Array<RouteRecordRaw> = [
{
path: '/audit',
component: AppLayout,
children: [{ path: '', component: () => import('./views/List.vue') }]
children: [
{ path: '', component: () => import('./views/List.vue') },
{ path: 'view/:id', component: () => import('./views/View.vue'), props: true }
]
}
]
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ArrowDown } from '@element-plus/icons-vue'
import { getAuditList, submitAudit } from '../api'
......@@ -42,8 +42,9 @@ const listOptions = computed(() => {
label: '状态',
options: [
{ label: '全部', value: '' },
{ label: '已审核', value: '1' },
{ label: '待审核', value: '2' }
{ label: '待审核', value: '2' },
{ label: '审核已通过', value: '1' },
{ label: '审核未通过', value: '3' }
]
}
],
......@@ -60,13 +61,19 @@ const onChangeType = (value: any) => {
tabActive.value = value
appList.value?.refetch()
}
const onAudit = (row: any, status: number) => {
submitAudit({ tab: tabActive.value, id: row.id, status, audit_comment: '' }).then(() => {
// 审核
const onAudit = (row: any, status: number, comment?: string) => {
submitAudit({ tab: tabActive.value, id: row.id, status, audit_comment: comment }).then(() => {
ElMessage({ type: 'success', message: '审核完成' })
appList.value?.refetch()
})
}
// 审核拒绝
const onAuditReject = (row: any, status: number) => {
ElMessageBox.prompt('请输入拒绝原因', '提示').then(({ value }) => {
onAudit(row, status, value)
})
}
</script>
<template>
......@@ -88,11 +95,11 @@ const onAudit = (row: any, status: number) => {
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="onAudit(row, 1)">通过</el-dropdown-item>
<el-dropdown-item @click="onAudit(row, 3)">拒绝</el-dropdown-item>
<el-dropdown-item @click="onAuditReject(row, 3)">拒绝</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<router-link :to="`/banner/view/${row.id}`">
<router-link :to="`/audit/view/${row.id}`" v-if="tabActive === 'course'">
<el-button plain type="primary">查看</el-button>
</router-link>
</el-space>
......
<script setup lang="ts">
import PublishItem from '@/components/PublishItem.vue'
import { getAudit } from '../api'
const props = defineProps<{ id: string }>()
let data = $ref<{ info: Record<string, any>; comments: { total: number; list: Record<string, any>[] } }>({
info: {},
comments: { total: 0, list: [] }
})
let loading = $ref<boolean>(false)
const getAuditInfo = () => {
loading = true
getAudit({ id: props.id, page_size: 100 })
.then(res => {
const { info, comments } = res.data
data = { info, comments }
})
.finally(() => {
loading = false
})
}
onMounted(() => {
getAuditInfo()
})
</script>
<template>
<AppCard v-loading="loading">
<PublishItem :info="data.info" :comments="data.comments" @remove="getAuditInfo"></PublishItem>
</AppCard>
</template>
......@@ -6,7 +6,7 @@ export function getQuestionList(params?: { name?: string; mobile?: string; page?
}
// 获取问题详情
export function getQuestion(params: { id: string }) {
export function getQuestion(params: { id: string; page_size?: number; page?: number }) {
return httpRequest.get('/api/psp/backend/question/view', { params })
}
......
......@@ -5,6 +5,9 @@ export const routes: Array<RouteRecordRaw> = [
{
path: '/qa',
component: AppLayout,
children: [{ path: '', component: () => import('./views/List.vue') }]
children: [
{ path: '', component: () => import('./views/List.vue') },
{ path: 'view/:id', component: () => import('./views/View.vue'), props: true }
]
}
]
......@@ -38,7 +38,7 @@ const onRemove = (row: any) => {
<AppList v-bind="listOptions" ref="appList">
<template #table-operate="{ row }">
<el-space>
<router-link :to="`/video/view/${row.id}`">
<router-link :to="`/qa/view/${row.id}`">
<el-button type="primary" plain>查看</el-button>
</router-link>
<el-button type="danger" plain @click="onRemove(row)">删除</el-button>
......
<script setup lang="ts">
import PublishItem from '@/components/PublishItem.vue'
import { getQuestion } from '../api'
const props = defineProps<{ id: string }>()
let data = $ref<{ info: Record<string, any>; comments: { total: number; list: Record<string, any>[] } }>({
info: {},
comments: { total: 0, list: [] }
})
let loading = $ref<boolean>(false)
const getQuestionInfo = () => {
loading = true
getQuestion({ id: props.id, page_size: 100 })
.then(res => {
const { info, comments } = res.data
data = { info, comments }
})
.finally(() => {
loading = false
})
}
onMounted(() => {
getQuestionInfo()
})
</script>
<template>
<AppCard v-loading="loading">
<h1 class="qa-title">{{ data.info.title }}</h1>
<PublishItem :info="data.info" :comments="data.comments" @remove="getQuestionInfo"></PublishItem>
</AppCard>
</template>
<style lang="scss" scoped>
.qa-title {
font-size: 20px;
margin-bottom: 20px;
}
</style>
......@@ -5,7 +5,6 @@ import { updateUser, getUser } from '../api'
const props = defineProps<{ id: string }>()
const router = useRouter()
const formRef = ref<FormInstance>()
const form = reactive({
name: '',
......
......@@ -56,3 +56,10 @@ onMounted(() => {
</el-tabs>
</AppCard>
</template>
<style lang="scss" scoped>
:deep(.el-descriptions__label) {
width: 100px;
text-align: center !important;
}
</style>
import httpRequest from '@/utils/axios'
// 获取学员列表
// 获取团队列表
export function getTeamList(params?: { name?: string; status?: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/psp/backend/team/index', { params })
}
// 团队审核
export function submitAudit(data: { id: string; status: number }) {
return httpRequest.post('/api/psp/backend/team/audit', data)
}
// 获取团队详情
export function getTeam(params: { id: string; page?: number; page_size?: number }) {
return httpRequest.get('/api/psp/backend/team/view', { params })
}
......@@ -5,6 +5,9 @@ export const routes: Array<RouteRecordRaw> = [
{
path: '/team',
component: AppLayout,
children: [{ path: '', component: () => import('./views/List.vue') }]
children: [
{ path: '', component: () => import('./views/List.vue') },
{ path: 'view/:id', component: () => import('./views/View.vue'), props: true }
]
}
]
<script setup lang="ts">
import { getTeamList } from '../api'
import { ElMessage } from 'element-plus'
import { getTeamList, submitAudit } from '../api'
const appList = ref()
const listOptions = {
remote: {
......@@ -29,15 +32,22 @@ const listOptions = {
{ label: '积分', prop: 'star' },
{ label: '资料数量', prop: 'files_count' },
{ label: '问答数量', prop: 'questions_count' },
{ label: '审核', prop: 'status', slots: 'table-status', width: 160, align: 'center' },
{ label: '操作', slots: 'table-operate', width: 100, align: 'right' }
{ label: '审核状态', prop: 'status_name' },
{ label: '操作', slots: 'table-operate', width: 180, align: 'right' }
]
}
// 审核
const onAudit = (row: any, status: number) => {
submitAudit({ id: row.id, status }).then(() => {
ElMessage({ type: 'success', message: '审核完成' })
appList.value?.refetch()
})
}
</script>
<template>
<AppCard>
<AppList v-bind="listOptions">
<AppList v-bind="listOptions" ref="appList">
<template #table-logo="{ row }">
<el-image
:src="row.logo + '?x-oss-process=image/resize,m_fill,h_100,w_200'"
......@@ -48,12 +58,23 @@ const listOptions = {
style="width: 200px; height: 100px"
/>
</template>
<template #table-status="{ row }">
<el-switch :value="row.status" active-text="通过" active-value="1" inactive-text="未通过" inactive-value="2" />
</template>
<template #table-operate>
<el-button>查看</el-button>
<template #table-operate="{ row }">
<el-space>
<el-dropdown v-if="row.status === '2'">
<el-button type="primary">
审核<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="onAudit(row, 1)">通过</el-dropdown-item>
<el-dropdown-item @click="onAudit(row, 0)">拒绝</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<router-link :to="`/team/view/${row.id}`">
<el-button plain type="primary">查看</el-button>
</router-link>
</el-space>
</template>
</AppList>
</AppCard>
......
<script setup lang="ts">
// import StarRecord from '../components/StarRecord.vue'
// import SignInRecord from '../components/SignInRecord.vue'
import { getTeam } from '../api'
const props = defineProps<{ id: string }>()
let data = ref()
let loading = ref<boolean>(false)
const getTeamInfo = () => {
loading.value = true
getTeam({ id: props.id }).then(res => {
data.value = res.data
loading.value = false
})
}
onMounted(() => {
getTeamInfo()
})
</script>
<template>
<AppCard title="团队信息" v-loading="loading">
<el-descriptions border v-if="data">
<el-descriptions-item label="名称">{{ data.info.name }}</el-descriptions-item>
<el-descriptions-item label="口号">{{ data.info.slogan }}</el-descriptions-item>
<el-descriptions-item label="星星数量">{{ data.info.star }}</el-descriptions-item>
<el-descriptions-item label="简介" :span="3">{{ data.info.brief }}</el-descriptions-item>
<el-descriptions-item label="Logo" :span="3">
<el-image :src="data.info.logo" style="width: 200px"></el-image>
</el-descriptions-item>
</el-descriptions>
</AppCard>
<AppCard>
<el-tabs type="card">
<el-tab-pane label="成员" lazy>
<!-- <SignInRecord :id="id"></SignInRecord> -->
</el-tab-pane>
<el-tab-pane label="资料" lazy>
<!-- <SignInRecord :id="id"></SignInRecord> -->
</el-tab-pane>
<el-tab-pane label="问答" lazy>
<!-- <StarRecord :id="id"></StarRecord> -->
</el-tab-pane>
</el-tabs>
</AppCard>
</template>
<style lang="scss" scoped>
:deep(.el-descriptions__label) {
width: 100px;
text-align: center !important;
}
</style>
......@@ -12,7 +12,7 @@ export default defineConfig(({ mode }) => {
base: mode === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/admin-prp/' : '/',
plugins: [
checker({ vueTsc: true, eslint: { lintCommand: 'eslint "./src/**/*.{vue,js,jsx,ts,tsx}"' } }),
vue(),
vue({ reactivityTransform: true }),
AutoImport({
imports: ['vue', 'vue/macros', 'vue-router', '@vueuse/core'],
dts: true,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论