Commit e0d3b4c8 by lijiabin

【需求 17679】 wip: 完善

parent 78e20c1b
......@@ -15,14 +15,11 @@ declare module 'vue' {
BaseButton: typeof import('./src/components/common/ElComponents/ElButton/BaseButton.vue')['default']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDatePickerPanel: typeof import('element-plus/es')['ElDatePickerPanel']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
......@@ -34,25 +31,20 @@ declare module 'vue' {
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElInput: typeof import('element-plus/es')['ElInput']
ElLink: typeof import('element-plus/es')['ElLink']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
......@@ -62,14 +54,8 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView']
SelectTags: typeof import('./src/components/common/SelectTags/index.vue')['default']
SvgIcon: typeof import('./src/components/common/SvgIcon/svgIcon.vue')['default']
Tabs: typeof import('./src/components/common/Tabs/index.tsx')['default']
TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
UploadFile: typeof import('./src/components/common/UploadFile/index.vue')['default']
UploadVideo: typeof import('./src/components/common/UploadVideo/index.vue')['default']
WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
}
export interface GlobalDirectives {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}
......@@ -78,14 +64,11 @@ declare global {
const BaseButton: typeof import('./src/components/common/ElComponents/ElButton/BaseButton.vue')['default']
const ElAvatar: typeof import('element-plus/es')['ElAvatar']
const ElButton: typeof import('element-plus/es')['ElButton']
const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
const ElCard: typeof import('element-plus/es')['ElCard']
const ElCarousel: typeof import('element-plus/es')['ElCarousel']
const ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
const ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
const ElDatePickerPanel: typeof import('element-plus/es')['ElDatePickerPanel']
const ElDialog: typeof import('element-plus/es')['ElDialog']
const ElDivider: typeof import('element-plus/es')['ElDivider']
const ElDropdown: typeof import('element-plus/es')['ElDropdown']
......@@ -97,25 +80,20 @@ declare global {
const ElIcon: typeof import('element-plus/es')['ElIcon']
const ElImage: typeof import('element-plus/es')['ElImage']
const ElInput: typeof import('element-plus/es')['ElInput']
const ElLink: typeof import('element-plus/es')['ElLink']
const ElOption: typeof import('element-plus/es')['ElOption']
const ElPagination: typeof import('element-plus/es')['ElPagination']
const ElPopover: typeof import('element-plus/es')['ElPopover']
const ElProgress: typeof import('element-plus/es')['ElProgress']
const ElRadio: typeof import('element-plus/es')['ElRadio']
const ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
const ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
const ElSelect: typeof import('element-plus/es')['ElSelect']
const ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
const ElSwitch: typeof import('element-plus/es')['ElSwitch']
const ElTable: typeof import('element-plus/es')['ElTable']
const ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
const ElTabPane: typeof import('element-plus/es')['ElTabPane']
const ElTabs: typeof import('element-plus/es')['ElTabs']
const ElTag: typeof import('element-plus/es')['ElTag']
const ElText: typeof import('element-plus/es')['ElText']
const ElTooltip: typeof import('element-plus/es')['ElTooltip']
const ElUpload: typeof import('element-plus/es')['ElUpload']
const HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
const IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
const IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
const IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
......@@ -125,9 +103,6 @@ declare global {
const RouterView: typeof import('vue-router')['RouterView']
const SelectTags: typeof import('./src/components/common/SelectTags/index.vue')['default']
const SvgIcon: typeof import('./src/components/common/SvgIcon/svgIcon.vue')['default']
const Tabs: typeof import('./src/components/common/Tabs/index.tsx')['default']
const TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
const UploadFile: typeof import('./src/components/common/UploadFile/index.vue')['default']
const UploadVideo: typeof import('./src/components/common/UploadVideo/index.vue')['default']
const WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
}
\ No newline at end of file
import service from '@/utils/request/index'
import type { AddOrUpdateArticleDto, ArticleItemDto, ArticleSearchParams } from './types'
import type { BackendServicePageResult } from '@/utils/request/types'
import { ArticleTypeEnum } from '@/constants'
// 文章相关的接口(帖子 视频 实践等)
/**
* 发布文章
*/
......
import service from '@/utils/request/index'
import type { AddOrUpdateCaseDto } from './types'
// 案例库相关的接口
/**
* 新增案例库
*/
export const addOrUpdateCase = (data: AddOrUpdateCaseDto) => {
return service.request({
url: '/api/cultureCase/addOrUpdateCase',
method: 'POST',
data,
})
}
/**
* 添加或更新案例库DTO
*/
export interface AddOrUpdateCaseDto {
content: string
title: string
tagList: number[]
}
import service from '@/utils/request/index'
import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
import type { TaskItemDto } from './types'
/**
* 获取任务列表
*/
export const getTaskList = (data: PageSearchParams) => {
return service.request<BackendServicePageResult<any>>({
export const getTaskList = () => {
return service.request<TaskItemDto[]>({
url: '/api/culture/task/config/getList',
method: 'POST',
data,
data: {},
})
}
import { TaskTypeEnum, TaskDateLimitTypeEnum } from '@/constants'
export interface TaskItemDto {
completedTasks: number
currentCount: number
description: string
id: number
jumpUrl: string
limitCount: number
limitType: TaskDateLimitTypeEnum
periodKey: string
rewardType: number
rewardValue: number
status: number
svgName: string
taskKey: string
taskType: TaskTypeEnum
title: string
totalTasks: number
}
......@@ -32,13 +32,13 @@
<div class="tags-grid">
<el-tag
v-for="tag in filteredRecommendedTags"
:key="tag.value"
:type="arryrOfModelValue.includes(tag.value) ? 'primary' : 'info'"
:effect="arryrOfModelValue.includes(tag.value) ? 'dark' : 'plain'"
:key="tag.id"
:type="arryrOfModelValue.includes(tag.id) ? 'primary' : 'info'"
:effect="arryrOfModelValue.includes(tag.id) ? 'dark' : 'plain'"
class="tag-item cursor-pointer mr-2 mb-2"
@click="toggleTag(tag.value)"
@click="toggleTag(tag.id)"
>
{{ tag.label }}
{{ tag.title }}
</el-tag>
</div>
</div>
......@@ -46,12 +46,12 @@
<div class="flex flex-wrap gap-2 mt-2">
<el-tag
v-for="tag in selectedTags"
:key="tag.value"
:key="tag.id"
closable
type="primary"
@close="removeTag(tag.value)"
@close="removeTag(tag.id)"
>
{{ tag.label }}
{{ tag.title }}
</el-tag>
</div>
</div>
......@@ -63,12 +63,11 @@
<script setup lang="ts" generic="T extends string | number[] | number">
import { useTagsStore } from '@/stores/tags'
import { storeToRefs } from 'pinia'
import type { TagItemDto } from '@/api/tag/types'
import type { SelectTagProps } from './types'
const { maxSelectedTags = 1, filterTagsFn } = defineProps<SelectTagProps>()
const emit = defineEmits<{
selected: [tag?: { value: number; label: string }]
selected: [tag?: TagItemDto]
}>()
const tagsStore = useTagsStore()
......@@ -91,14 +90,14 @@ const arryrOfModelValue = computed({
get() {
if (isArrayOfModelValue) {
return (modelValue.value as number[]).filter((tagId) => {
return filterTags.value.some((tag) => tag.value === tagId)
return filterTags.value.some((tag) => tag.id === tagId)
})
}
return (modelValue.value as string)
.split(',')
.filter(Boolean)
.map(Number)
.filter((tagId) => filterTags.value.some((tag) => tag.value === tagId))
.filter((tagId) => filterTags.value.some((tag) => tag.id === tagId))
},
set(value) {
if (isArrayOfModelValue) {
......@@ -110,14 +109,11 @@ const arryrOfModelValue = computed({
})
// 选中的标签
const selectedTags = computed(() => {
const selectedTags: { value: number; label: string }[] = []
const selectedTags: TagItemDto[] = []
arryrOfModelValue.value.forEach((tagId) => {
const tag = filterTags.value.find((tag) => tag.value === tagId)
const tag = filterTags.value.find((tag) => tag.id === tagId)
if (tag) {
selectedTags.push({
value: tag.value,
label: tag.label,
})
selectedTags.push(tag)
}
})
return selectedTags
......@@ -130,7 +126,7 @@ const filteredRecommendedTags = computed(() => {
return filterTags.value
}
return filterTags.value.filter((tag) =>
tag.label.toLowerCase().includes(searchKeyword.value.toLowerCase()),
tag.title.toLowerCase().includes(searchKeyword.value.toLowerCase()),
)
})
......@@ -140,10 +136,7 @@ const addTag = (tagId: number) => {
// 不能直接push 触发不了computed 的 set
arryrOfModelValue.value = [...arryrOfModelValue.value, tagId]
ElMessage.success('标签添加成功')
emit('selected', {
label: filterTags.value.find((tag) => tag.value === tagId)!.label,
value: tagId,
})
emit('selected', filterTags.value.find((tag) => tag.id === tagId)!)
}
const removeTag = (tagId: number) => {
......
import type { TagItemDto } from '@/api/tag/types'
export type SelectTagProps = {
maxSelectedTags?: number
filterTagsFn?: (tags: { value: number; label: string }[]) => { value: number; label: string }[]
filterTagsFn?: (tags: TagItemDto[]) => TagItemDto[]
}
......@@ -43,3 +43,13 @@ export enum SendTypeEnum {
// 定时发送
SCHEDULED = 2,
}
// 任务日期限制类型枚举
export enum TaskDateLimitTypeEnum {
// 每日
DAY = 'DAY',
// 每周
WEEK = 'WEEK',
// 每月
MONTH = 'MONTH',
}
export * from './options'
export * from './enums'
export * from './symbolKey'
export * from './text'
import { TaskDateLimitTypeEnum } from './enums'
// 枚举中文映射
export const TaskDateLimitTypeText: Record<TaskDateLimitTypeEnum, string> = {
[TaskDateLimitTypeEnum.DAY]: '日',
[TaskDateLimitTypeEnum.WEEK]: '周',
[TaskDateLimitTypeEnum.MONTH]: '月',
}
......@@ -8,14 +8,11 @@
<div class="cursor-pointer online-time flex flex-col items-center z-50">
<!-- 图片容器 -->
<div
class="relative mb-2 hover:scale-105 transition-transform duration-300 ease-out transform-gpu backface-hidden"
class="mb-4 w-24 h-24 bg-white rounded-full shadow-xl flex items-center justify-center hover:scale-110 transition-transform cursor-pointer"
>
<img
draggable="false"
src="@/assets/img/culture/online_time.png"
alt="在线时长"
class="w-16 h-16 md:w-20 md:h-20"
/>
<img src="@/assets/img/culture/ask.png" draggable="false" alt="吉祥物" class="w-20 h-20" />
<!-- 如果没有图片,用emoji代替 -->
<!-- <span class="text-6xl">🎯</span> -->
</div>
<!-- 时长显示卡片 -->
......@@ -39,7 +36,7 @@
今日在线时长
</div>
<div
class="text-lg md:text-xl lg:text-2xl font-bold text-gray-800 font-mono tracking-wider"
class="text-center text-2xl font-bold bg-gradient-to-r from-blue-500 to-purple-500 bg-clip-text text-transparent"
>
00:00
</div>
......
......@@ -4,6 +4,7 @@ import UploadFile from '@/components/common/UploadFile/index.vue'
import SelectTags from '@/components/common/SelectTags/index.vue'
import { useResetData } from '@/hooks'
import type { TagItemDto } from '@/api/tag/types'
export default defineComponent((_, { expose }) => {
const [form, resetForm] = useResetData({
......@@ -52,9 +53,9 @@ export default defineComponent((_, { expose }) => {
}
}
const filterTagsFn = (allTags: { value: number; label: string }[]) => {
const filterTagsFn = (allTags: TagItemDto[]) => {
// 引用了form.value.mainTagId
return allTags.filter((tag) => tag.value !== Number(form.value.mainTagId))
return allTags.filter((tag) => tag.id !== Number(form.value.mainTagId))
}
const resetFields = () => {
......
......@@ -5,6 +5,7 @@
:close-on-click-modal="false"
width="500px"
class="post-dialog"
:lock-scroll="true"
align-center
@closed="handleClosed"
>
......
<template>
<div class="layout-culture pb-11 h-full bg-[linear-gradient(to_bottom,#F0FBFD_0%,#ECEFFF_100%)]">
<div
class="header flex px-40 items-center justify-between bg-white mb-1 shadow-sm fixed top-0 left-0 right-0 z-10"
class="header flex px-40 items-center justify-between bg-white mb-1 shadow-sm fixed top-0 left-0 right-0 z-10 w-100vw"
>
<!-- Logo区域 -->
<div @click="router.push('/')" class="flex items-center flex-shrink-0 min-w-0 cursor-pointer">
......
......@@ -5,30 +5,31 @@ const routes = [
path: '/',
name: 'Layout',
component: layoutCulture,
redirect: '/mainContainer/deshboard',
redirect: '/homePage/homeTab',
meta: {
title: '企业文化首页',
},
children: [
{
path: 'mainContainer',
name: 'CultureMainContainer',
component: () => import('@/layoutCulture/components/mainContainer.vue'),
path: 'homePage',
name: 'CultureHomePage',
// component: () => import('@/layoutCulture/components/mainContainer.vue'),
component: () => import('@/views/homePage/index.vue'),
children: [
{
path: 'deshboard',
name: 'CultureHome',
component: () => import('@/views/home/index.vue'),
path: 'homeTab',
name: 'CultureHomeTab',
component: () => import('@/views/homePage/homeTab/index.vue'),
},
{
path: 'ya',
name: 'CultureYa',
component: () => import('@/views/ya/index.vue'),
path: 'yaTab',
name: 'CultureYaTab',
component: () => import('@/views/homePage/yaTab/index.vue'),
},
{
path: 'ask',
name: 'CultureAsk',
component: () => import('@/views/ask/index.vue'),
path: 'askTab',
name: 'CultureAskTab',
component: () => import('@/views/homePage/askTab/index.vue'),
},
],
},
......@@ -53,18 +54,18 @@ const routes = [
name: 'CulturePublishVideo',
component: () => import('@/views/publishVideo/index.vue'),
},
// 发布文章
{
path: 'postArticle',
name: 'CulturePostArticle',
component: () => import('@/views/postArticle/index.vue'),
},
// 个人中心
{
path: 'userPage',
name: 'CultureUserPage',
component: () => import('@/views/userPage/index.vue'),
},
// 去投稿
{
path: 'publishCase',
name: 'CulturePublishCase',
component: () => import('@/views/publishCase/index.vue'),
},
// 发布文章
// {
// {
......
import { defineStore } from 'pinia'
import { getTagList } from '@/api'
import type { TagItemDto } from '@/api/tag/types'
/**
* 关于标签的store
*/
export const useTagsStore = defineStore('tags', () => {
const tagList = ref<{ label: string; value: number }[]>([])
const tagList = ref<TagItemDto[]>([])
let isLoading = false
......@@ -15,10 +15,8 @@ export const useTagsStore = defineStore('tags', () => {
isLoading = true
try {
const { data } = await getTagList()
tagList.value = data.map((item) => ({
label: item.title,
value: item.id,
}))
tagList.value = data
console.log(tagList.value, 'tagList')
} catch (error) {
console.error(error)
} finally {
......
......@@ -6,7 +6,7 @@ import type { LoginResponseDto } from '@/api/login/types'
*/
export const useUserStore = defineStore('user', () => {
const userInfo = ref({} as LoginResponseDto)
const token = ref('')
const token = ref(localStorage.getItem('token') || '')
// 获取用户信息
const fetchUserInfo = async () => {
const { data } = await loginByEmail({
......
@import './reset.css';
/* 解决弹窗滚轮 */
......@@ -48,6 +48,8 @@ export default class DhRequest {
if (response.headers.authorization) {
const userStore = useUserStore()
userStore.setToken(response.headers.authorization)
// 存在本地
localStorage.setItem('token', response.headers.authorization)
}
return response.data
} else {
......
......@@ -98,7 +98,7 @@
<el-button
class="bg-[linear-gradient(to_right,#A3EADC_0%,#7BE0BD_100%)] shadow-[0_1px_4px_0_rgba(168,225,210,1)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm"
type="primary"
@click="openPostCaseDialog"
@click="router.push('/publishCase')"
>
<svg-icon name="submit" size="30" class="mr-2" />
<span class="text-black text-xs sm:text-sm">去投稿</span>
......@@ -161,33 +161,49 @@
</div>
<div class="flex flex-col gap-2 sm:gap-3">
<div v-for="item in regularTaskList" :key="item.id">
<div
class="flex items-center justify-between hover:bg-white/10 rounded-lg transition-colors duration-200 group"
>
<div class="flex items-center min-w-0 flex-1">
<svg-icon name="daily_sign" size="70" />
<div class="flex flex-col items-start justify-center ml-2 sm:ml-3 min-w-0 flex-1">
<div class="text-xs sm:text-sm truncate w-full font-medium">
{{ item.title }}
<div v-show="currentTaskList.length">
<div v-for="item in currentTaskList" :key="item.id">
<div
class="flex items-center justify-between hover:bg-white/10 rounded-lg transition-colors duration-200 group"
>
<div class="flex items-center min-w-0 flex-1">
<div class="h-70px flex items-center justify-center">
<svg-icon :name="item.svgName" size="50" />
</div>
<div class="color-#757575 text-xs w-full flex items-start flex-nowrap">
<svg-icon name="small_coin" size="16" class="mr-1" />
<el-tooltip :content="item.description" placement="top">
<div class="truncate w-130px cursor-pointer">{{ item.description }}</div>
</el-tooltip>
<div
class="flex flex-col items-start justify-center ml-2 sm:ml-3 min-w-0 flex-1"
>
<div class="text-14px truncate w-full font-medium mb-1">
{{ item.title }}
</div>
<div class="color-#333 text-xs w-full flex items-center flex-nowrap">
<svg-icon name="small_coin" size="16" class="mr-1" />
<el-tooltip :content="item.description" placement="top">
<div class="truncate w-130px cursor-pointer">
+{{ item.rewardValue }}亚币{{
TaskDateLimitTypeText[item.limitType] &&
`(${TaskDateLimitTypeText[item.limitType] + '刷新'})`
}}
</div>
</el-tooltip>
</div>
</div>
</div>
<el-button
class="bg-[linear-gradient(to_right,#FFC5A1_0%,#FFB77F_100%)] shadow-[0_1px_8px_0_rgba(255,141,54,0.25)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm rounded-full"
type="primary"
>
<span class="text-black text-xs sm:text-sm">去签到</span>
</el-button>
</div>
<el-button
class="bg-[linear-gradient(to_right,#FFC5A1_0%,#FFB77F_100%)] shadow-[0_1px_8px_0_rgba(255,141,54,0.25)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm rounded-full"
type="primary"
>
<span class="text-black text-xs sm:text-sm">去签到</span>
</el-button>
<!-- 分割线 -->
<el-divider style="margin: 0" />
</div>
</div>
<div v-show="currentTaskList.length === 0">
<div class="flex items-center justify-center">
<el-empty :image-size="100" description="暂无任务" />
</div>
<!-- 分割线 -->
<el-divider style="margin: 0" />
</div>
</div>
</div>
......@@ -202,9 +218,8 @@ import ya from '@/assets/img/culture/ya_culture.png'
import ask from '@/assets/img/culture/ask.png'
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router'
import { getTaskList, dailySign, getCarouselList } from '@/api'
import { usePageSearch } from '@/hooks'
import { TaskTypeEnum } from '@/constants'
import type { CarouselItemDto } from '@/api'
import { TaskTypeEnum, TaskDateLimitTypeText } from '@/constants'
import type { CarouselItemDto, TaskItemDto } from '@/api'
import { TABS_REF_KEY } from '@/constants'
const route = useRoute()
......@@ -222,6 +237,10 @@ const tabs = [
const activeTab = ref(
tabs.find((item) => item.path === route.path.split('/').at(-1))?.name || '首页',
)
const toggleTab = (tab: { name: string; path: string }) => {
activeTab.value = tab.name
router.push(`/homePage/${tab.path}`)
}
const taskTypeList = [
{
......@@ -236,26 +255,18 @@ const taskTypeList = [
const currentTask = ref(TaskTypeEnum.REGULAR_TASK)
const toggleTab = (tab: { name: string; path: string }) => {
activeTab.value = tab.name
console.log(tab.path)
router.push(`/homePage/${tab.path}`)
}
const regularTaskList = ref<TaskItemDto[]>([])
const specialTaskList = ref<TaskItemDto[]>([])
const currentTaskList = computed(() =>
currentTask.value === TaskTypeEnum.REGULAR_TASK ? regularTaskList.value : specialTaskList.value,
)
const getThirdLevelKey = (route: RouteLocationNormalizedLoadedGeneric) => {
// console.log(route, '三级路由')
return route.fullPath
}
const { list, total } = usePageSearch(getTaskList)
const regularTaskList = computed(() =>
list.value.filter((item) => item.taskType === TaskTypeEnum.REGULAR_TASK),
)
const specialTaskList = computed(() =>
list.value.filter((item) => item.taskType === TaskTypeEnum.SPECIAL_TASK),
)
const onDailySign = async () => {
await dailySign()
}
......@@ -264,12 +275,27 @@ const openPostCaseDialog = () => {
console.log('openPostCaseDialog')
}
provide(TABS_REF_KEY, tabsRef)
const initPage = () => {
Promise.allSettled([getCarouselList(), getTaskList()]).then(([r1, r2]) => {
if (r1.status === 'fulfilled') {
carouselList.value = r1.value.data
}
if (r2.status === 'fulfilled') {
regularTaskList.value = r2.value.data.filter(
(item) => item.taskType === TaskTypeEnum.REGULAR_TASK,
)
specialTaskList.value = r2.value.data.filter(
(item) => item.taskType === TaskTypeEnum.SPECIAL_TASK,
)
}
})
}
onMounted(async () => {
const { data } = await getCarouselList()
carouselList.value = data
onMounted(() => {
initPage()
})
provide(TABS_REF_KEY, tabsRef)
</script>
<style lang="scss" scoped>
.main-container {
......
<template>
<div class="min-h-screen bg-gradient-to-br">
<div class="max-w-4xl mx-auto">
<!-- 主表单卡片 -->
<div class="bg-white rounded-2xl shadow-lg p-8">
<el-form ref="formRef" :model="form" label-position="top" size="default">
<!-- 案例编号 -->
<div class="mb-6 flex items-center gap-2">
<span class="text-gray-700 font-medium">案例编号:</span>
<span class="text-gray-900 font-semibold">000001</span>
<el-tooltip content="案例编号自动生成" placement="top">
<el-icon class="text-pink-500 cursor-pointer">
<QuestionFilled />
</el-icon>
</el-tooltip>
</div>
<!-- 标题输入 -->
<el-form-item class="mb-6" label="标题">
<el-input
v-model="form.title"
placeholder="请输入【案例】标题"
:maxlength="100"
show-word-limit
size="large"
class="text-lg"
/>
</el-form-item>
<!-- 内容输入 -->
<el-form-item class="mb-6 relative" label="内容">
<el-input
v-model="form.content"
type="textarea"
placeholder="添加案例文本内容..."
:rows="12"
:maxlength="5000"
show-word-limit
/>
</el-form-item>
<!-- 关键词选择 -->
<el-form-item label="文化关键词" class="mb-6">
<div class="flex flex-wrap gap-3">
<SelectTags v-model="form.tagList" />
</div>
</el-form-item>
<!-- 上传人 -->
<el-form-item class="mb-6" label="上传人">
<el-input
v-model="form.uploadUser"
placeholder="请输入【案例】上传人"
:maxlength="100"
show-word-limit
size="large"
class="text-lg"
/>
</el-form-item>
<!-- 上传时间 -->
<el-form-item class="mb-6" label="上传时间">
<el-input v-model="form.uploadTime" placeholder="请输入【案例】上传时间" />
</el-form-item>
<!-- 是否同步发布 -->
<el-form-item label="*是否同步发布到实践" class="mb-6">
<el-radio-group v-model="form.publishToPractice">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
<!-- 发布时间 -->
<el-form-item label="*发布时间" class="mb-8">
<el-radio-group v-model="form.publishTime">
<el-radio label="now">立即发布</el-radio>
<el-radio label="scheduled">定时发布</el-radio>
</el-radio-group>
<el-date-picker
v-if="form.publishTime === 'scheduled'"
v-model="form.scheduledTime"
type="datetime"
placeholder="选择发布时间"
class="ml-4"
/>
</el-form-item>
<!-- 底部按钮组 -->
<div class="flex items-center justify-between gap-4 pt-4">
<div class="flex gap-4">
<el-button size="large" @click="handleCancel"> 取消 </el-button>
<el-button size="large" @click="handlePreview"> 预览 </el-button>
<el-button size="large" type="info" plain @click="handleSaveDraft">
存草稿
</el-button>
</div>
<el-button type="primary" @click="handleSubmit"> 提交 </el-button>
</div>
</el-form>
</div>
</div>
</div>
</template>
<script setup lang="tsx">
import { QuestionFilled } from '@element-plus/icons-vue'
import { addOrUpdateCase } from '@/api/case'
import { useResetData } from '@/hooks'
import type { AddOrUpdateCaseDto } from '@/api/case/types'
import SelectTags from '@/components/common/SelectTags/index.vue'
import type { FormInstance } from 'element-plus'
const formRef = useTemplateRef<FormInstance>('formRef')
const [form, resetForm] = useResetData<AddOrUpdateCaseDto>({
title: '',
content: '',
tagList: [],
})
// 取消
const handleCancel = () => {
ElMessage.warning('确定要取消吗?')
// 可以添加确认对话框
}
// 预览
const handlePreview = () => {
console.log('预览', form)
ElMessage.success('预览功能待实现')
}
// 保存草稿
const handleSaveDraft = () => {
console.log('保存草稿', form)
ElMessage.success('草稿保存成功')
}
// 提交
const handleSubmit = async () => {
await formRef.value?.validate()
const res = await addOrUpdateCase(form.value)
if (res) {
ElMessage.success('提交成功')
}
}
const showSubmissionGuide = () => {
const countdown = ref(0)
let timer: number | null = null
const MessageContent = (): VNode => {
return (
<div>
<div class="px-5 py-4 leading-7">
<div class="mb-4 text-base">
1YA伙伴实名投稿,分享您在工作中践行公司文化或解决实际业务的成功案例与经验。
</div>
<div class="mb-1 text-base">2、投稿时,您可自主选择:</div>
<div class="text-sm mb-1">
1)公开公示:案例将实名展示YA文化“实践”版块,成为全员可见的光荣榜,用于分享、激励和学习。
</div>
<div class="text-sm mb-4">
2)私有入库:案例将直接进入亚声内部案例管理系统,作为宝贵的内部知识资产供管理层分析和参考,分析参考时不会展示分享人信息。
</div>
<div class="mb-4 text-base">
3、通过奖品激励与光荣榜展示,鼓励伙伴分享,在尊重伙伴个人意愿的同时,将优秀实践经验沉淀为组织财富,实现个人成长与团队赋能的双赢。
</div>
<div class="flex justify-center pt-3 border-t border-[#ebeef5]">
<el-button
type="primary"
disabled={countdown.value > 0}
loading={countdown.value > 0}
onClick={() => {
if (countdown.value === 0) {
ElMessageBox.close()
}
}}
>
{countdown.value > 0 ? `${countdown.value}s` : '确定'}
</el-button>
</div>
</div>
</div>
)
}
timer = setInterval(() => {
if (countdown.value > 0) {
countdown.value--
} else {
if (timer) clearInterval(timer)
}
}, 1000)
ElMessageBox({
title: '投稿说明',
center: true,
message: MessageContent,
lockScroll: true,
showConfirmButton: false,
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
})
}
onActivated(() => {
showSubmissionGuide()
})
</script>
<style scoped>
:deep(.el-textarea__inner) {
font-size: 15px;
line-height: 1.6;
}
:deep(.el-input__inner) {
font-size: 16px;
}
/* 渐变背景文字 */
.text-transparent {
-webkit-text-fill-color: transparent;
}
</style>
......@@ -49,7 +49,8 @@ export default defineConfig({
// https: false as const,
proxy: {
'/api1': {
target: 'http://192.168.2.168:8089', // 首拥本地
// target: 'http://192.168.2.168:8089', // 立鹏本地
target: 'http://192.168.2.55:8089', // 首拥本地
changeOrigin: true,
rewrite: (path) => {
return path.replace(/^\/api1/, '')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment