显示员工申请须知+显示课程购买须知
This commit is contained in:
BIN
dist---TOP.zip
Normal file
BIN
dist---TOP.zip
Normal file
Binary file not shown.
BIN
dist160-9092.zip
Normal file
BIN
dist160-9092.zip
Normal file
Binary file not shown.
BIN
dist8月15日9092.zip
Normal file
BIN
dist8月15日9092.zip
Normal file
Binary file not shown.
@ -7,7 +7,7 @@ import router from "../router";
|
|||||||
const myAxios = axios.create({
|
const myAxios = axios.create({
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
// baseURL:'http://localhost:9091'
|
// baseURL:'http://localhost:9091'
|
||||||
// baseURL:'http://localhost:9092'
|
baseURL:'http://localhost:9092'
|
||||||
// baseURL:'http://1.94.237.210:3457'
|
// baseURL:'http://1.94.237.210:3457'
|
||||||
//baseURL:'http://1.94.237.210:8088'
|
//baseURL:'http://1.94.237.210:8088'
|
||||||
//baseURL:'http://27.30.77.229:9091/'
|
//baseURL:'http://27.30.77.229:9091/'
|
||||||
@ -15,7 +15,7 @@ const myAxios = axios.create({
|
|||||||
// baseURL:'http://160.202.242.36:9091/'
|
// baseURL:'http://160.202.242.36:9091/'
|
||||||
// baseURL:'http://160.202.242.36:9092/'
|
// baseURL:'http://160.202.242.36:9092/'
|
||||||
// baseURL:'http://160.202.242.36:9092'
|
// baseURL:'http://160.202.242.36:9092'
|
||||||
baseURL:'https://www.chenxinzhi.top'
|
// baseURL:'https://www.chenxinzhi.top'
|
||||||
});
|
});
|
||||||
|
|
||||||
myAxios.interceptors.request.use(function (config) {
|
myAxios.interceptors.request.use(function (config) {
|
||||||
|
@ -7,8 +7,22 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<div v-if="loadingBanners" class="loading-container">
|
||||||
|
<a-spin size="large" />
|
||||||
|
<p class="loading-text">轮播图加载中...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 错误提示 -->
|
||||||
|
<div v-if="bannerError" class="error-container">
|
||||||
|
<a-alert type="error" :message="bannerError" show-icon />
|
||||||
|
<a-button type="primary" @click="fetchBanners" class="retry-button">
|
||||||
|
重新加载
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 轮播图展示 -->
|
<!-- 轮播图展示 -->
|
||||||
<a-carousel arrows class="carouselContainer">
|
<a-carousel v-if="!loadingBanners && !bannerError && banners.length > 0" arrows class="carouselContainer">
|
||||||
<template #prevArrow>
|
<template #prevArrow>
|
||||||
<div class="custom-slick-arrow" style="left: 10px; z-index: 1">
|
<div class="custom-slick-arrow" style="left: 10px; z-index: 1">
|
||||||
<left-circle-outlined />
|
<left-circle-outlined />
|
||||||
@ -28,6 +42,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</a-carousel>
|
</a-carousel>
|
||||||
|
|
||||||
|
<!-- 空状态提示 -->
|
||||||
|
<div v-if="!loadingBanners && !bannerError && banners.length === 0" class="empty-container">
|
||||||
|
<a-empty description="暂无轮播图数据">
|
||||||
|
<a-button type="primary" @click="showAddModal">添加轮播图</a-button>
|
||||||
|
</a-empty>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 新增弹框 -->
|
<!-- 新增弹框 -->
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="addModalVisible"
|
v-model:visible="addModalVisible"
|
||||||
@ -104,7 +125,7 @@ import {
|
|||||||
CloseCircleOutlined,
|
CloseCircleOutlined,
|
||||||
DeleteOutlined
|
DeleteOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import { message } from 'ant-design-vue';
|
import { message, Spin as ASpin, Alert as AAlert, Empty as AEmpty } from 'ant-design-vue';
|
||||||
import type { UploadChangeParam } from 'ant-design-vue';
|
import type { UploadChangeParam } from 'ant-design-vue';
|
||||||
import myAxios from "../../api/myAxios.ts";
|
import myAxios from "../../api/myAxios.ts";
|
||||||
|
|
||||||
@ -129,6 +150,11 @@ const currentBannerUrl = ref('');
|
|||||||
const currentBannerId = ref('');
|
const currentBannerId = ref('');
|
||||||
const currentBannerIndex = ref(-1);
|
const currentBannerIndex = ref(-1);
|
||||||
|
|
||||||
|
// 新增:加载状态和错误状态
|
||||||
|
const loadingBanners = ref(true);
|
||||||
|
const bannerError = ref('');
|
||||||
|
|
||||||
|
|
||||||
// 获取上传URL和请求头
|
// 获取上传URL和请求头
|
||||||
const uploadUrl = `${myAxios.defaults.baseURL}/file/upload`;
|
const uploadUrl = `${myAxios.defaults.baseURL}/file/upload`;
|
||||||
const uploadHeaders = {
|
const uploadHeaders = {
|
||||||
@ -302,6 +328,8 @@ const handleDeleteBanner = async () => {
|
|||||||
|
|
||||||
// 获取轮播图列表
|
// 获取轮播图列表
|
||||||
const fetchBanners = async () => {
|
const fetchBanners = async () => {
|
||||||
|
loadingBanners.value = true;
|
||||||
|
bannerError.value = '';
|
||||||
try {
|
try {
|
||||||
const response:any = await myAxios.get('/banner/web/list', {
|
const response:any = await myAxios.get('/banner/web/list', {
|
||||||
headers: {
|
headers: {
|
||||||
@ -321,6 +349,8 @@ const fetchBanners = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取轮播图失败:', error);
|
console.error('获取轮播图失败:', error);
|
||||||
message.error('获取轮播图失败');
|
message.error('获取轮播图失败');
|
||||||
|
}finally {
|
||||||
|
loadingBanners.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -331,6 +361,53 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* 加载状态样式 */
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 40px;
|
||||||
|
height: 300px;
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 20px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 错误状态样式 */
|
||||||
|
.error-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 30px;
|
||||||
|
background: #fff1f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 20px auto;
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.retry-button {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态样式 */
|
||||||
|
.empty-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 40px;
|
||||||
|
background: #fafafa;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 20px auto;
|
||||||
|
max-width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
/* 按钮样式 */
|
/* 按钮样式 */
|
||||||
.add-button-container {
|
.add-button-container {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
@ -70,7 +70,7 @@ const editorConfig = {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (res.code === 1) {
|
if (res.code === 1) {
|
||||||
|
// const imageUrl = 'http://160.202.242.36:9092/file/download/' + res.data
|
||||||
const imageUrl = 'https://www.chenxinzhi.top/file/download/' + res.data
|
const imageUrl = 'https://www.chenxinzhi.top/file/download/' + res.data
|
||||||
insertFn(imageUrl)
|
insertFn(imageUrl)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<form @submit.prevent="handleSubmit" class="modern-form">
|
<div class="modern-form">
|
||||||
<h2 class="form-title">课程购买须知</h2>
|
<h2 class="form-title">课程购买须知</h2>
|
||||||
|
<!-- 只读模式 -->
|
||||||
|
<div v-if="!editing" class="readonly-container">
|
||||||
|
<div class="notice-content" v-html="decodedNotice"></div>
|
||||||
|
<button @click="startEditing" class="edit-button">
|
||||||
|
<span>修改须知</span>
|
||||||
|
<div class="button-sparkles"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- 编辑模式 -->
|
||||||
|
<form v-else @submit.prevent="handleSubmit" class="editing-form">
|
||||||
<!-- 富文本编辑器 -->
|
<!-- 富文本编辑器 -->
|
||||||
<div class="rich-text-container">
|
<div class="rich-text-container">
|
||||||
<div class="rich-text-group">
|
<div class="rich-text-group">
|
||||||
@ -19,12 +28,17 @@
|
|||||||
<div v-if="errorMessage" class="error-message">
|
<div v-if="errorMessage" class="error-message">
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="button-group">
|
||||||
|
<button type="button" @click="cancelEditing" class="cancel-button">
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
<button type="submit" class="submit-button">
|
<button type="submit" class="submit-button">
|
||||||
<span>保存须知</span>
|
<span>保存须知</span>
|
||||||
<div class="button-sparkles"></div>
|
<div class="button-sparkles"></div>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -45,6 +59,20 @@ const formData = reactive<NoticeForm>({
|
|||||||
const editorRef = ref<InstanceType<typeof RichTextEditor> | null>(null);
|
const editorRef = ref<InstanceType<typeof RichTextEditor> | null>(null);
|
||||||
const errorMessage = ref('');
|
const errorMessage = ref('');
|
||||||
const editorContent = ref('');
|
const editorContent = ref('');
|
||||||
|
const decodedNotice = ref('<p>加载课程须知中...</p>');
|
||||||
|
const editing = ref(false);
|
||||||
|
|
||||||
|
// Base64解码函数
|
||||||
|
const decode64 = (base64Text: string): string => {
|
||||||
|
if (!base64Text.trim()) return '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(escape(atob(base64Text)));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Base64解码失败:', error);
|
||||||
|
return '内容解析错误';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 增强Base64编码方法
|
// 增强Base64编码方法
|
||||||
const encode64 = (text: string): string => {
|
const encode64 = (text: string): string => {
|
||||||
@ -83,6 +111,46 @@ const isContentEmpty = (html: string): boolean => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取申请须知
|
||||||
|
const fetchNotice = async () => {
|
||||||
|
try {
|
||||||
|
const storedToken = localStorage.getItem('token');
|
||||||
|
const res: any = await myAxios.post(
|
||||||
|
`/userInfo/query/courseDesc`,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': storedToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.code === 1 && res.data) {
|
||||||
|
decodedNotice.value = decode64(res.data);
|
||||||
|
} else {
|
||||||
|
decodedNotice.value = `<p class="error-text">获取购买须知失败: ${res.message || '未知错误'}</p>`;
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('获取须知失败:', error);
|
||||||
|
decodedNotice.value = `<p class="error-text">网络错误,请稍后重试</p>`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始编辑
|
||||||
|
const startEditing = () => {
|
||||||
|
editing.value = true;
|
||||||
|
// 将当前内容加载到编辑器
|
||||||
|
editorContent.value = decodedNotice.value;
|
||||||
|
formData.templateString = decodedNotice.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消编辑
|
||||||
|
const cancelEditing = () => {
|
||||||
|
editing.value = false;
|
||||||
|
errorMessage.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
@ -119,6 +187,9 @@ const handleSubmit = async () => {
|
|||||||
);
|
);
|
||||||
console.log(res)
|
console.log(res)
|
||||||
if (res.code === 1) {
|
if (res.code === 1) {
|
||||||
|
decodedNotice.value = formData.templateString;
|
||||||
|
editing.value = false;
|
||||||
|
errorMessage.value = '';
|
||||||
alert('须知保存成功!');
|
alert('须知保存成功!');
|
||||||
|
|
||||||
if (editorRef.value) {
|
if (editorRef.value) {
|
||||||
@ -155,12 +226,12 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
// 初始化时清空错误信息
|
// 初始化时清空错误信息
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
fetchNotice();
|
||||||
errorMessage.value = '';
|
errorMessage.value = '';
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.modern-form {
|
.modern-form {
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
@ -180,6 +251,52 @@ onMounted(() => {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.readonly-container {
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content {
|
||||||
|
min-height: 300px;
|
||||||
|
padding: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content :deep(p) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content :deep(.error-text) {
|
||||||
|
color: #e53e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 20px rgba(16, 185, 129, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
.label-text {
|
.label-text {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 0.6rem;
|
margin-bottom: 0.6rem;
|
||||||
@ -200,13 +317,18 @@ onMounted(() => {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.submit-button {
|
.submit-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
flex: 1;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-top: 1.5rem;
|
|
||||||
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
@ -219,6 +341,26 @@ onMounted(() => {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #4a5568;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button:hover {
|
||||||
|
background: #cbd5e0;
|
||||||
|
}
|
||||||
|
|
||||||
.submit-button:hover {
|
.submit-button:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.3);
|
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.3);
|
||||||
@ -286,6 +428,8 @@ onMounted(() => {
|
|||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
}
|
}
|
||||||
|
.button-group {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -1,30 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<form @submit.prevent="handleSubmit" class="modern-form">
|
<div class="modern-form">
|
||||||
<h2 class="form-title">员工账号申请须知</h2>
|
<h2 class="form-title">员工申请须知</h2>
|
||||||
|
|
||||||
<!-- 富文本编辑器 -->
|
<!-- 只读模式 -->
|
||||||
<div class="rich-text-container">
|
<div v-if="!editing" class="readonly-container">
|
||||||
<div class="rich-text-group">
|
<div class="notice-content" v-html="decodedNotice"></div>
|
||||||
<span class="label-text">须知详情</span>
|
<button @click="startEditing" class="edit-button">
|
||||||
<RichTextEditor
|
<span>修改须知</span>
|
||||||
ref="editorRef"
|
<div class="button-sparkles"></div>
|
||||||
:value="editorContent"
|
</button>
|
||||||
:disable="false"
|
</div>
|
||||||
@content-change="handleEditorChange"
|
|
||||||
/>
|
<!-- 编辑模式 -->
|
||||||
|
<form v-else @submit.prevent="handleSubmit" class="editing-form">
|
||||||
|
<div class="rich-text-container">
|
||||||
|
<div class="rich-text-group">
|
||||||
|
<span class="label-text">须知详情</span>
|
||||||
|
<RichTextEditor
|
||||||
|
ref="editorRef"
|
||||||
|
:value="editorContent"
|
||||||
|
:disable="false"
|
||||||
|
@content-change="handleEditorChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 错误提示 -->
|
<div v-if="errorMessage" class="error-message">
|
||||||
<div v-if="errorMessage" class="error-message">
|
{{ errorMessage }}
|
||||||
{{ errorMessage }}
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="submit-button">
|
<div class="button-group">
|
||||||
<span>保存须知</span>
|
<button type="button" @click="cancelEditing" class="cancel-button">
|
||||||
<div class="button-sparkles"></div>
|
取消
|
||||||
</button>
|
</button>
|
||||||
</form>
|
<button type="submit" class="submit-button">
|
||||||
|
<span>保存须知</span>
|
||||||
|
<div class="button-sparkles"></div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -33,7 +48,6 @@ import RichTextEditor from '../components/RichTextEditor.vue';
|
|||||||
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||||
import myAxios from "../../api/myAxios.ts";
|
import myAxios from "../../api/myAxios.ts";
|
||||||
|
|
||||||
|
|
||||||
interface NoticeForm {
|
interface NoticeForm {
|
||||||
templateString: string;
|
templateString: string;
|
||||||
}
|
}
|
||||||
@ -45,13 +59,26 @@ const formData = reactive<NoticeForm>({
|
|||||||
const editorRef = ref<InstanceType<typeof RichTextEditor> | null>(null);
|
const editorRef = ref<InstanceType<typeof RichTextEditor> | null>(null);
|
||||||
const errorMessage = ref('');
|
const errorMessage = ref('');
|
||||||
const editorContent = ref('');
|
const editorContent = ref('');
|
||||||
|
const decodedNotice = ref('<p>加载申请须知中...</p>');
|
||||||
|
const editing = ref(false);
|
||||||
|
|
||||||
// 增强Base64编码方法
|
// Base64解码函数
|
||||||
|
const decode64 = (base64Text: string): string => {
|
||||||
|
if (!base64Text.trim()) return '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(escape(atob(base64Text)));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Base64解码失败:', error);
|
||||||
|
return '内容解析错误';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base64编码函数
|
||||||
const encode64 = (text: string): string => {
|
const encode64 = (text: string): string => {
|
||||||
if (!text.trim()) return '';
|
if (!text.trim()) return '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return btoa(unescape(encodeURIComponent(text)));
|
return btoa(unescape(encodeURIComponent(text)));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Base64编码失败:', error);
|
console.error('Base64编码失败:', error);
|
||||||
@ -59,23 +86,18 @@ const encode64 = (text: string): string => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleEditorChange = (html: string) => {
|
const handleEditorChange = (html: string) => {
|
||||||
formData.templateString = html;
|
formData.templateString = html;
|
||||||
editorContent.value = html;
|
editorContent.value = html;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const isContentEmpty = (html: string): boolean => {
|
const isContentEmpty = (html: string): boolean => {
|
||||||
if (!html) return true;
|
if (!html) return true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const tempDiv = document.createElement('div');
|
const tempDiv = document.createElement('div');
|
||||||
tempDiv.innerHTML = html;
|
tempDiv.innerHTML = html;
|
||||||
|
|
||||||
const plainText = tempDiv.textContent || '';
|
const plainText = tempDiv.textContent || '';
|
||||||
|
|
||||||
return plainText.trim() === '';
|
return plainText.trim() === '';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('内容解析失败:', error);
|
console.error('内容解析失败:', error);
|
||||||
@ -83,6 +105,46 @@ const isContentEmpty = (html: string): boolean => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取申请须知
|
||||||
|
const fetchNotice = async () => {
|
||||||
|
try {
|
||||||
|
const storedToken = localStorage.getItem('token');
|
||||||
|
const res: any = await myAxios.post(
|
||||||
|
`/userInfo/query/applyNotice`,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': storedToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.code === 1 && res.data) {
|
||||||
|
decodedNotice.value = decode64(res.data);
|
||||||
|
} else {
|
||||||
|
decodedNotice.value = `<p class="error-text">获取申请须知失败: ${res.message || '未知错误'}</p>`;
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('获取须知失败:', error);
|
||||||
|
decodedNotice.value = `<p class="error-text">网络错误,请稍后重试</p>`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始编辑
|
||||||
|
const startEditing = () => {
|
||||||
|
editing.value = true;
|
||||||
|
// 将当前内容加载到编辑器
|
||||||
|
editorContent.value = decodedNotice.value;
|
||||||
|
formData.templateString = decodedNotice.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消编辑
|
||||||
|
const cancelEditing = () => {
|
||||||
|
editing.value = false;
|
||||||
|
errorMessage.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
@ -95,7 +157,6 @@ const handleSubmit = async () => {
|
|||||||
|
|
||||||
const encryptedContent = encode64(formData.templateString);
|
const encryptedContent = encode64(formData.templateString);
|
||||||
|
|
||||||
|
|
||||||
if (!encryptedContent) {
|
if (!encryptedContent) {
|
||||||
errorMessage.value = '内容加密失败,请检查输入内容';
|
errorMessage.value = '内容加密失败,请检查输入内容';
|
||||||
return;
|
return;
|
||||||
@ -105,9 +166,6 @@ const handleSubmit = async () => {
|
|||||||
templateString: encryptedContent
|
templateString: encryptedContent
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('提交内容:', formData.templateString);
|
|
||||||
console.log('加密内容:', encryptedContent);
|
|
||||||
|
|
||||||
const res: any = await myAxios.post(
|
const res: any = await myAxios.post(
|
||||||
`/userInfo/modify/applyNotice`,
|
`/userInfo/modify/applyNotice`,
|
||||||
payload,
|
payload,
|
||||||
@ -118,31 +176,26 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
console.log(res)
|
|
||||||
if (res.code === 1) {
|
|
||||||
alert('须知保存成功!');
|
|
||||||
|
|
||||||
if (editorRef.value) {
|
if (res.code === 1) {
|
||||||
editorRef.value.clearContent();
|
// 更新本地内容并退出编辑模式
|
||||||
}
|
decodedNotice.value = formData.templateString;
|
||||||
formData.templateString = '';
|
editing.value = false;
|
||||||
editorContent.value = '';
|
|
||||||
errorMessage.value = '';
|
errorMessage.value = '';
|
||||||
|
alert('须知保存成功!');
|
||||||
} else {
|
} else {
|
||||||
errorMessage.value = `保存失败:${res.message || '服务器错误'} (${res.code})`;
|
errorMessage.value = `保存失败:${res.message || '服务器错误'} (${res.code})`;
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('请求失败:', error);
|
console.error('请求失败:', error);
|
||||||
|
|
||||||
let detailedError = '提交失败:';
|
let detailedError = '提交失败:';
|
||||||
if (error.response) {
|
|
||||||
|
|
||||||
|
if (error.response) {
|
||||||
const serverMessage = error.response.data?.message ||
|
const serverMessage = error.response.data?.message ||
|
||||||
error.response.data?.error ||
|
error.response.data?.error ||
|
||||||
'无详细错误信息';
|
'无详细错误信息';
|
||||||
detailedError += `服务器响应错误 (${error.response.status}): ${serverMessage}`;
|
detailedError += `服务器响应错误 (${error.response.status}): ${serverMessage}`;
|
||||||
|
|
||||||
|
|
||||||
if (error.response.data?.code === 40000) {
|
if (error.response.data?.code === 40000) {
|
||||||
detailedError = '须知内容不能为空';
|
detailedError = '须知内容不能为空';
|
||||||
}
|
}
|
||||||
@ -156,14 +209,13 @@ const handleSubmit = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化时清空错误信息
|
// 初始化时获取申请须知
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
errorMessage.value = '';
|
fetchNotice();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.modern-form {
|
.modern-form {
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
@ -183,6 +235,52 @@ onMounted(() => {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.readonly-container {
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content {
|
||||||
|
min-height: 300px;
|
||||||
|
padding: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content :deep(p) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content :deep(.error-text) {
|
||||||
|
color: #e53e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 20px rgba(16, 185, 129, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
.label-text {
|
.label-text {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 0.6rem;
|
margin-bottom: 0.6rem;
|
||||||
@ -203,13 +301,18 @@ onMounted(() => {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.submit-button {
|
.submit-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
flex: 1;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-top: 1.5rem;
|
|
||||||
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
@ -222,6 +325,26 @@ onMounted(() => {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #4a5568;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button:hover {
|
||||||
|
background: #cbd5e0;
|
||||||
|
}
|
||||||
|
|
||||||
.submit-button:hover {
|
.submit-button:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.3);
|
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.3);
|
||||||
@ -289,6 +412,8 @@ onMounted(() => {
|
|||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
}
|
}
|
||||||
|
.button-group {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
Reference in New Issue
Block a user