企业宣传

master
xhj 5 days ago
parent 96eaf584c1
commit 7ece66f7a6

@ -43,7 +43,6 @@
"clipboard": "2.0.8", "clipboard": "2.0.8",
"core-js": "3.19.1", "core-js": "3.19.1",
"echarts": "4.9.0", "echarts": "4.9.0",
"v-charts": "^1.19.0",
"element-ui": "2.15.8", "element-ui": "2.15.8",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"fuse.js": "6.4.3", "fuse.js": "6.4.3",
@ -54,16 +53,20 @@
"kr-print-designer": "^1.1.8", "kr-print-designer": "^1.1.8",
"moment": "^2.24.0", "moment": "^2.24.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "1.3.7", "quill": "^1.3.7",
"quill-image-extend-module": "^1.1.2",
"screenfull": "5.0.2", "screenfull": "5.0.2",
"sortablejs": "1.10.2", "sortablejs": "1.10.2",
"v-charts": "^1.19.0",
"vue": "2.6.12", "vue": "2.6.12",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-cropper": "0.5.5", "vue-cropper": "0.5.5",
"vue-meta": "2.4.0", "vue-meta": "2.4.0",
"vue-quill-editor": "^3.0.6",
"vue-router": "3.4.9", "vue-router": "3.4.9",
"vuedraggable": "2.24.3", "vuedraggable": "2.24.3",
"vuex": "3.6.0" "vuex": "3.6.0",
"wangeditor": "^4.7.15"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "4.4.6", "@vue/cli-plugin-babel": "4.4.6",

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询瑜伽欣赏列表
export function listAppreciate(query) {
return request({
url: '/system/appreciate/list',
method: 'get',
params: query
})
}
// 查询瑜伽欣赏详细
export function getAppreciate(id) {
return request({
url: '/system/appreciate/' + id,
method: 'get'
})
}
// 新增瑜伽欣赏
export function addAppreciate(data) {
return request({
url: '/system/appreciate',
method: 'post',
data: data
})
}
// 修改瑜伽欣赏
export function updateAppreciate(data) {
return request({
url: '/system/appreciate',
method: 'put',
data: data
})
}
// 删除瑜伽欣赏
export function delAppreciate(id) {
return request({
url: '/system/appreciate/' + id,
method: 'delete'
})
}

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询健康饮食列表
export function listHealthy(query) {
return request({
url: '/system/healthy/list',
method: 'get',
params: query
})
}
// 查询健康饮食详细
export function getHealthy(id) {
return request({
url: '/system/healthy/' + id,
method: 'get'
})
}
// 新增健康饮食
export function addHealthy(data) {
return request({
url: '/system/healthy',
method: 'post',
data: data
})
}
// 修改健康饮食
export function updateHealthy(data) {
return request({
url: '/system/healthy',
method: 'put',
data: data
})
}
// 删除健康饮食
export function delHealthy(id) {
return request({
url: '/system/healthy/' + id,
method: 'delete'
})
}

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询瑜伽传承列表
export function listInherit(query) {
return request({
url: '/system/inherit/list',
method: 'get',
params: query
})
}
// 查询瑜伽传承详细
export function getInherit(id) {
return request({
url: '/system/inherit/' + id,
method: 'get'
})
}
// 新增瑜伽传承
export function addInherit(data) {
return request({
url: '/system/inherit',
method: 'post',
data: data
})
}
// 修改瑜伽传承
export function updateInherit(data) {
return request({
url: '/system/inherit',
method: 'put',
data: data
})
}
// 删除瑜伽传承
export function delInherit(id) {
return request({
url: '/system/inherit/' + id,
method: 'delete'
})
}
// 新增瑜伽传承
export function getInheritBase(data) {
return request({
url: '/system/inherit/getBase',
method: 'post',
data: data
})
}

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询【请填写功能名称】列表
export function listMoments(query) {
return request({
url: '/system/moments/list',
method: 'get',
params: query
})
}
// 查询【请填写功能名称】详细
export function getMoments(id) {
return request({
url: '/system/moments/' + id,
method: 'get'
})
}
// 新增【请填写功能名称】
export function addMoments(data) {
return request({
url: '/system/moments',
method: 'post',
data: data
})
}
// 修改【请填写功能名称】
export function updateMoments(data) {
return request({
url: '/system/moments',
method: 'put',
data: data
})
}
// 删除【请填写功能名称】
export function delMoments(id) {
return request({
url: '/system/moments/' + id,
method: 'delete'
})
}

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询瑜伽常识列表
export function listSense(query) {
return request({
url: '/system/sense/list',
method: 'get',
params: query
})
}
// 查询瑜伽常识详细
export function getSense(id) {
return request({
url: '/system/sense/' + id,
method: 'get'
})
}
// 新增瑜伽常识
export function addSense(data) {
return request({
url: '/system/sense',
method: 'post',
data: data
})
}
// 修改瑜伽常识
export function updateSense(data) {
return request({
url: '/system/sense',
method: 'put',
data: data
})
}
// 删除瑜伽常识
export function delSense(id) {
return request({
url: '/system/sense/' + id,
method: 'delete'
})
}

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询门店列表
export function listStore(query) {
return request({
url: '/system/store/list',
method: 'get',
params: query
})
}
// 查询门店详细
export function getStore(deptId) {
return request({
url: '/system/store/' + deptId,
method: 'get'
})
}
// 新增门店
export function addStore(data) {
return request({
url: '/system/store',
method: 'post',
data: data
})
}
// 修改门店
export function updateStore(data) {
return request({
url: '/system/store',
method: 'put',
data: data
})
}
// 删除门店
export function delStore(deptId) {
return request({
url: '/system/store/' + deptId,
method: 'delete'
})
}

@ -0,0 +1,51 @@
import request from '@/utils/request'
// 查询员工信息列表
export function listTeacher(query) {
return request({
url: '/system/teacher/list',
method: 'get',
params: query
})
}
// 查询员工信息详细
export function getTeacher(userId) {
return request({
url: '/system/teacher/' + userId,
method: 'get'
})
}
// 新增员工信息
export function addTeacher(data) {
return request({
url: '/system/teacher',
method: 'post',
data: data
})
}
// 修改员工信息
export function updateTeacher(data) {
return request({
url: '/system/teacher',
method: 'put',
data: data
})
}
// export function delTeacher(data) {
// return request({
// url: '/system/teacher/remove', // 后端接收批量删除的接口地址(需与后端一致)
// method: 'post', // 改为POST方法
// data: data // 请求体传递ids数组
// });
// }
export function delTeacher(ids) {
return request({
url: '/system/teacher/remove',
method: 'post',
data: ids // 注意:这里直接传数组,不是{ids: ids}
});
}

@ -9,6 +9,13 @@ export function listUser(query) {
params: query params: query
}) })
} }
export function listAll(query) {
return request({
url: '/system/user/listAll',
method: 'get',
params: query
})
}
// 查询用户详细 // 查询用户详细
export function getUser(userId) { export function getUser(userId) {

@ -0,0 +1,730 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="不展示" value="0"></el-option>
<el-option label="展示" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:inherit:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:inherit:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="inheritList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" align="center" prop="id" />
<!-- <el-table-column label="门店/校区id" align="center" prop="deptId" >-->
<!-- <template v-for="item in scope.row.deptId">-->
<!-- &lt;!&ndash; <span></span>&ndash;&gt;-->
<!-- <el-tag type="sucess" v-if="item!=''" style="float: left">{{ memberFormat(item) }}</el-tag>-->
<!-- &lt;!&ndash; <span>{{ item }}</span>&ndash;&gt;-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- 门店/校区名称标签形式 -->
<el-table-column label="门店/校区名称" align="center">
<template #default="scope">
<!-- 调用方法获取名称用span或el-tag展示 -->
<el-tag type="info">{{ getDeptName(scope.row.deptId) }}</el-tag>
<!-- 若不需要样式直接用span<span>{{ getDeptName(scope.row.deptId) }}</span> -->
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="封面" align="center" prop="image" width="100">
<template slot-scope="scope">
<el-image
:src="getFullImgUrl(scope.row.image)"
:preview-src-list="[getFullImgUrl(scope.row.image)]"
style="width: 50px; height: 50px;"
fit="cover"
:lazy="false"
></el-image>
</template>
</el-table-column>
<el-table-column label="阅读量" align="center" prop="readNum" />
<el-table-column label="内容" align="center" prop="content" width="120">
<template slot-scope="scope">
<el-button
type="text"
@click="showContentDialog(scope.row.content)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="是否展示" align="center" prop="status" width="120">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? '展示' : '不展示' }}
</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="创建时间" align="center" prop="startTime" width="180">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="更新时间" align="center" prop="modifyTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.modifyTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改瑜伽传承对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 标题表单项后添加 -->
<el-form-item label="门店/校区" prop="deptId">
<el-select
v-model="form.deptId"
placeholder="请选择门店/校区"
clearable
style="width: 100%"
>
<!-- 遍历deptList渲染选项deptId为值deptName为显示文本 -->
<el-option
v-for="dept in deptList"
:key="dept.deptId"
:label="dept.deptName"
:value="dept.deptId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入标题" />
</el-form-item>
<!-- 封面上传区域 -->
<el-form-item label="封面" prop="image">
<el-upload
class="image-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload"
:headers="uploadHeaders"
:disabled="isUploading"
>
<el-image
v-if="form.image"
:src="getFullImgUrl(form.image)"
style="width: 150px; height: 100px;"
fit="cover"
:lazy="false"
>
<div slot="error" class="image-error">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<i v-else class="el-icon-plus image-uploader-icon"></i>
<el-loading
v-if="isUploading"
text="上传中..."
target=".image-uploader"
background="rgba(255,255,255,0.8)"
></el-loading>
</el-upload>
</el-form-item>
<el-form-item label="阅读量" prop="readNum">
<el-input v-model.number="form.readNum" placeholder="请输入阅读量" />
</el-form-item>
<el-form-item label="内容" prop="content">
<div class="editor-container">
<div ref="editor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
<el-form-item label="是否展示" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="0">不展示</el-radio>
<el-radio label="1">展示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 内容查看对话框 -->
<el-dialog
title="内容详情"
:visible.sync="contentDialogVisible"
width="800px"
:before-close="handleDialogClose"
>
<div v-html="contentDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import {getInheritBase} from "@/api/columns/inherit";
import { listAppreciate, getAppreciate, delAppreciate, addAppreciate, updateAppreciate } from "@/api/columns/appreciate";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Practice",
components: {
Pagination,
RightToolbar
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
inheritList: [],
deptList:[],
//
title: "",
//
open: false,
//
contentDialogVisible: false,
contentDialogContent: "",
//
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
//
editor: null,
//
queryParams: {
pageNum: 1,
pageSize: 10,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: null,
modifyTime: null,
deptId: null,
},
//
form: {
status: "0" //
},
//
rules: {
title: [
{ required: true, message: "请输入标题", trigger: "blur" }
],
image: [
{ required: true, message: "请上传封面图片", trigger: "change" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
]
}
};
},
created() {
this.getList();
this.getBase();
},
methods: {
/** 对话框打开后回调 */
onDialogOpened() {
if (!this.editor) {
this.initEditor();
}
},
getDeptName(deptId) {
if (!deptId) return '未设置';
// deptList
// const dept = this.deptList.find(item => item.deptId === deptId);
// return dept ? dept.deptName : '';
for(let e of this.deptList){
if(deptId==e.deptId){
return deptId ? e.deptName : '未知部门';
}
}
},
/** 初始化富文本编辑器 */
initEditor() {
if (this.$refs.editor) {
this.editor = new WangEditor(this.$refs.editor);
//
this.editor.config.showLinkImg = false;
//
this.editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.content = this.editor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('富文本图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.editor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.content = processedHtml;
};
//
this.editor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.editor.create();
} else {
setTimeout(() => this.initEditor(), 100);
}
},
getBase(){
getInheritBase().then(res=>{
console.log(res)
this.deptList=res.data
})
},
/** 查询瑜伽传承列表 */
getList() {
this.loading = true;
listAppreciate(this.queryParams).then(response => {
this.inheritList = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 显示内容对话框 */
showContentDialog(content) {
let processedContent = content || '';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.contentDialogContent = processedContent;
this.contentDialogVisible = true;
},
/** 关闭内容对话框 */
handleDialogClose() {
this.contentDialogContent = "";
this.contentDialogVisible = false;
},
/** 处理封面上传成功 */
handleImageSuccess(response) {
this.isUploading = false;
if (response && response.code === 200 && response.data) {
this.form.image = response.data;
this.$nextTick(() => {
this.$message.success('封面上传成功');
});
} else {
this.$message.error('上传失败:' + (response.msg || '返回格式错误'));
}
},
/** 封面上传前校验 */
beforeImageUpload(file) {
this.isUploading = true;
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.isUploading = false;
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.isUploading = false;
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: "0",
modifyTime: null,
deptId: null
};
this.resetForm("form");
if (this.editor) {
this.editor.txt.clear();
}
this.isUploading = false;
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加瑜伽传承";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids[0];
if (!id) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getAppreciate(id).then(response => {
this.form = { ...response.data };
this.form.status = String(this.form.status || "0");
//
this.$nextTick(() => {
setTimeout(() => {
if (this.editor && this.form.content) {
const processedHtml = this.form.content.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.editor.txt.html(processedHtml);
}
}, 500);
});
this.open = true;
this.title = "修改瑜伽传承";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交按钮 */
submitForm() {
//
if (this.editor) {
const html = this.editor.txt.html();
//
if (html.includes('<img') && html.includes('src=""')) {
this.$message.error('存在无效图片,请重新上传');
return;
}
this.form.content = html;
}
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateAppreciate(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("修改失败");
});
} else {
addAppreciate(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("新增失败");
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
if (!ids || (Array.isArray(ids) && ids.length === 0)) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm('是否确认删除瑜伽传承编号为"' + ids + '"的数据项?').then(function() {
return delAppreciate(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/inherit/export', {
...this.queryParams
}, `inherit_${new Date().getTime()}.xlsx`)
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
}
},
beforeDestroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
};
</script>
<style scoped>
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
/* 图片上传样式 */
.image-uploader {
position: relative;
display: inline-block;
}
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 4px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 150px;
height: 100px;
line-height: 100px;
text-align: center;
}
/* 图片错误样式 */
.image-error {
width: 150px;
height: 100px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
color: #8c939d;
}
</style>

@ -0,0 +1,731 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="不展示" value="0"></el-option>
<el-option label="展示" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:inherit:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:inherit:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="inheritList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" align="center" prop="id" />
<!-- <el-table-column label="门店/校区id" align="center" prop="deptId" >-->
<!-- <template v-for="item in scope.row.deptId">-->
<!-- &lt;!&ndash; <span></span>&ndash;&gt;-->
<!-- <el-tag type="sucess" v-if="item!=''" style="float: left">{{ memberFormat(item) }}</el-tag>-->
<!-- &lt;!&ndash; <span>{{ item }}</span>&ndash;&gt;-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- 门店/校区名称标签形式 -->
<el-table-column label="门店/校区名称" align="center">
<template #default="scope">
<!-- 调用方法获取名称用span或el-tag展示 -->
<el-tag type="info">{{ getDeptName(scope.row.deptId) }}</el-tag>
<!-- 若不需要样式直接用span<span>{{ getDeptName(scope.row.deptId) }}</span> -->
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="封面" align="center" prop="image" width="100">
<template slot-scope="scope">
<el-image
:src="getFullImgUrl(scope.row.image)"
:preview-src-list="[getFullImgUrl(scope.row.image)]"
style="width: 50px; height: 50px;"
fit="cover"
:lazy="false"
></el-image>
</template>
</el-table-column>
<el-table-column label="阅读量" align="center" prop="readNum" />
<el-table-column label="内容" align="center" prop="content" width="120">
<template slot-scope="scope">
<el-button
type="text"
@click="showContentDialog(scope.row.content)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="是否展示" align="center" prop="status" width="120">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? '展示' : '不展示' }}
</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="创建时间" align="center" prop="startTime" width="180">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="更新时间" align="center" prop="modifyTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.modifyTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改瑜伽传承对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 标题表单项后添加 -->
<el-form-item label="门店/校区" prop="deptId">
<el-select
v-model="form.deptId"
placeholder="请选择门店/校区"
clearable
style="width: 100%"
>
<!-- 遍历deptList渲染选项deptId为值deptName为显示文本 -->
<el-option
v-for="dept in deptList"
:key="dept.deptId"
:label="dept.deptName"
:value="dept.deptId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入标题" />
</el-form-item>
<!-- 封面上传区域 -->
<el-form-item label="封面" prop="image">
<el-upload
class="image-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload"
:headers="uploadHeaders"
:disabled="isUploading"
>
<el-image
v-if="form.image"
:src="getFullImgUrl(form.image)"
style="width: 150px; height: 100px;"
fit="cover"
:lazy="false"
>
<div slot="error" class="image-error">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<i v-else class="el-icon-plus image-uploader-icon"></i>
<el-loading
v-if="isUploading"
text="上传中..."
target=".image-uploader"
background="rgba(255,255,255,0.8)"
></el-loading>
</el-upload>
</el-form-item>
<el-form-item label="阅读量" prop="readNum">
<el-input v-model.number="form.readNum" placeholder="请输入阅读量" />
</el-form-item>
<el-form-item label="内容" prop="content">
<div class="editor-container">
<div ref="editor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
<el-form-item label="是否展示" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="0">不展示</el-radio>
<el-radio label="1">展示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 内容查看对话框 -->
<el-dialog
title="内容详情"
:visible.sync="contentDialogVisible"
width="800px"
:before-close="handleDialogClose"
>
<div v-html="contentDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import {getInheritBase} from "@/api/columns/inherit";
import { listHealthy, getHealthy, delHealthy, addHealthy, updateHealthy } from "@/api/columns/healthy";
// import { listHealthy, getHealthy, delHealthy, addHealthy, updateHealthy } from "@/api/system/healthy";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Health",
components: {
Pagination,
RightToolbar
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
inheritList: [],
deptList:[],
//
title: "",
//
open: false,
//
contentDialogVisible: false,
contentDialogContent: "",
//
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
//
editor: null,
//
queryParams: {
pageNum: 1,
pageSize: 10,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: null,
modifyTime: null,
deptId: null,
},
//
form: {
status: "0" //
},
//
rules: {
title: [
{ required: true, message: "请输入标题", trigger: "blur" }
],
image: [
{ required: true, message: "请上传封面图片", trigger: "change" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
]
}
};
},
created() {
this.getList();
this.getBase();
},
methods: {
/** 对话框打开后回调 */
onDialogOpened() {
if (!this.editor) {
this.initEditor();
}
},
getDeptName(deptId) {
if (!deptId) return '未设置';
// deptList
// const dept = this.deptList.find(item => item.deptId === deptId);
// return dept ? dept.deptName : '';
for(let e of this.deptList){
if(deptId==e.deptId){
return deptId ? e.deptName : '未知部门';
}
}
},
/** 初始化富文本编辑器 */
initEditor() {
if (this.$refs.editor) {
this.editor = new WangEditor(this.$refs.editor);
//
this.editor.config.showLinkImg = false;
//
this.editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.content = this.editor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('富文本图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.editor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.content = processedHtml;
};
//
this.editor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.editor.create();
} else {
setTimeout(() => this.initEditor(), 100);
}
},
getBase(){
getInheritBase().then(res=>{
console.log(res)
this.deptList=res.data
})
},
/** 查询瑜伽传承列表 */
getList() {
this.loading = true;
listHealthy(this.queryParams).then(response => {
this.inheritList = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 显示内容对话框 */
showContentDialog(content) {
let processedContent = content || '';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.contentDialogContent = processedContent;
this.contentDialogVisible = true;
},
/** 关闭内容对话框 */
handleDialogClose() {
this.contentDialogContent = "";
this.contentDialogVisible = false;
},
/** 处理封面上传成功 */
handleImageSuccess(response) {
this.isUploading = false;
if (response && response.code === 200 && response.data) {
this.form.image = response.data;
this.$nextTick(() => {
this.$message.success('封面上传成功');
});
} else {
this.$message.error('上传失败:' + (response.msg || '返回格式错误'));
}
},
/** 封面上传前校验 */
beforeImageUpload(file) {
this.isUploading = true;
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.isUploading = false;
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.isUploading = false;
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: "0",
modifyTime: null,
deptId: null
};
this.resetForm("form");
if (this.editor) {
this.editor.txt.clear();
}
this.isUploading = false;
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加瑜伽传承";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids[0];
if (!id) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getHealthy(id).then(response => {
this.form = { ...response.data };
this.form.status = String(this.form.status || "0");
//
this.$nextTick(() => {
setTimeout(() => {
if (this.editor && this.form.content) {
const processedHtml = this.form.content.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.editor.txt.html(processedHtml);
}
}, 500);
});
this.open = true;
this.title = "修改瑜伽传承";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交按钮 */
submitForm() {
//
if (this.editor) {
const html = this.editor.txt.html();
//
if (html.includes('<img') && html.includes('src=""')) {
this.$message.error('存在无效图片,请重新上传');
return;
}
this.form.content = html;
}
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateHealthy(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("修改失败");
});
} else {
addHealthy(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("新增失败");
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
if (!ids || (Array.isArray(ids) && ids.length === 0)) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm('是否确认删除瑜伽传承编号为"' + ids + '"的数据项?').then(function() {
return delHealthy(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/inherit/export', {
...this.queryParams
}, `inherit_${new Date().getTime()}.xlsx`)
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
}
},
beforeDestroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
};
</script>
<style scoped>
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
/* 图片上传样式 */
.image-uploader {
position: relative;
display: inline-block;
}
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 4px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 150px;
height: 100px;
line-height: 100px;
text-align: center;
}
/* 图片错误样式 */
.image-error {
width: 150px;
height: 100px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
color: #8c939d;
}
</style>

@ -0,0 +1,728 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="不展示" value="0"></el-option>
<el-option label="展示" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:inherit:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:inherit:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="inheritList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" align="center" prop="id" />
<!-- <el-table-column label="门店/校区id" align="center" prop="deptId" >-->
<!-- <template v-for="item in scope.row.deptId">-->
<!-- &lt;!&ndash; <span></span>&ndash;&gt;-->
<!-- <el-tag type="sucess" v-if="item!=''" style="float: left">{{ memberFormat(item) }}</el-tag>-->
<!-- &lt;!&ndash; <span>{{ item }}</span>&ndash;&gt;-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- 门店/校区名称标签形式 -->
<el-table-column label="门店/校区名称" align="center">
<template #default="scope">
<!-- 调用方法获取名称用span或el-tag展示 -->
<el-tag type="info">{{ getDeptName(scope.row.deptId) }}</el-tag>
<!-- 若不需要样式直接用span<span>{{ getDeptName(scope.row.deptId) }}</span> -->
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="封面" align="center" prop="image" width="100">
<template slot-scope="scope">
<el-image
:src="getFullImgUrl(scope.row.image)"
:preview-src-list="[getFullImgUrl(scope.row.image)]"
style="width: 50px; height: 50px;"
fit="cover"
:lazy="false"
></el-image>
</template>
</el-table-column>
<el-table-column label="阅读量" align="center" prop="readNum" />
<el-table-column label="内容" align="center" prop="content" width="120">
<template slot-scope="scope">
<el-button
type="text"
@click="showContentDialog(scope.row.content)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="是否展示" align="center" prop="status" width="120">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? '展示' : '不展示' }}
</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="创建时间" align="center" prop="startTime" width="180">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="更新时间" align="center" prop="modifyTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.modifyTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改瑜伽传承对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 标题表单项后添加 -->
<el-form-item label="门店/校区" prop="deptId">
<el-select
v-model="form.deptId"
placeholder="请选择门店/校区"
clearable
style="width: 100%"
>
<!-- 遍历deptList渲染选项deptId为值deptName为显示文本 -->
<el-option
v-for="dept in deptList"
:key="dept.deptId"
:label="dept.deptName"
:value="dept.deptId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入标题" />
</el-form-item>
<!-- 封面上传区域 -->
<el-form-item label="封面" prop="image">
<el-upload
class="image-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload"
:headers="uploadHeaders"
:disabled="isUploading"
>
<el-image
v-if="form.image"
:src="getFullImgUrl(form.image)"
style="width: 150px; height: 100px;"
fit="cover"
:lazy="false"
>
<div slot="error" class="image-error">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<i v-else class="el-icon-plus image-uploader-icon"></i>
<el-loading
v-if="isUploading"
text="上传中..."
target=".image-uploader"
background="rgba(255,255,255,0.8)"
></el-loading>
</el-upload>
</el-form-item>
<el-form-item label="阅读量" prop="readNum">
<el-input v-model.number="form.readNum" placeholder="请输入阅读量" />
</el-form-item>
<el-form-item label="内容" prop="content">
<div class="editor-container">
<div ref="editor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
<el-form-item label="是否展示" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="0">不展示</el-radio>
<el-radio label="1">展示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 内容查看对话框 -->
<el-dialog
title="内容详情"
:visible.sync="contentDialogVisible"
width="800px"
:before-close="handleDialogClose"
>
<div v-html="contentDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import {listInherit, getInherit, delInherit, addInherit, updateInherit, getInheritBase} from "@/api/columns/inherit";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Inherit",
components: {
Pagination,
RightToolbar
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
inheritList: [],
deptList:[],
//
title: "",
//
open: false,
//
contentDialogVisible: false,
contentDialogContent: "",
//
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
//
editor: null,
//
queryParams: {
pageNum: 1,
pageSize: 10,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: null,
modifyTime: null,
deptId: null,
},
//
form: {
status: "0" //
},
//
rules: {
title: [
{ required: true, message: "请输入标题", trigger: "blur" }
],
image: [
{ required: true, message: "请上传封面图片", trigger: "change" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
]
}
};
},
created() {
this.getList();
this.getBase();
},
methods: {
/** 对话框打开后回调 */
onDialogOpened() {
if (!this.editor) {
this.initEditor();
}
},
getDeptName(deptId) {
if (!deptId) return '未设置';
// deptList
// const dept = this.deptList.find(item => item.deptId === deptId);
// return dept ? dept.deptName : '';
for(let e of this.deptList){
if(deptId==e.deptId){
return deptId ? e.deptName : '未知部门';
}
}
},
/** 初始化富文本编辑器 */
initEditor() {
if (this.$refs.editor) {
this.editor = new WangEditor(this.$refs.editor);
//
this.editor.config.showLinkImg = false;
//
this.editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.content = this.editor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('富文本图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.editor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.content = processedHtml;
};
//
this.editor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.editor.create();
} else {
setTimeout(() => this.initEditor(), 100);
}
},
getBase(){
getInheritBase().then(res=>{
console.log(res)
this.deptList=res.data
})
},
/** 查询瑜伽传承列表 */
getList() {
this.loading = true;
listInherit(this.queryParams).then(response => {
this.inheritList = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 显示内容对话框 */
showContentDialog(content) {
let processedContent = content || '';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.contentDialogContent = processedContent;
this.contentDialogVisible = true;
},
/** 关闭内容对话框 */
handleDialogClose() {
this.contentDialogContent = "";
this.contentDialogVisible = false;
},
/** 处理封面上传成功 */
handleImageSuccess(response) {
this.isUploading = false;
if (response && response.code === 200 && response.data) {
this.form.image = response.data;
this.$nextTick(() => {
this.$message.success('封面上传成功');
});
} else {
this.$message.error('上传失败:' + (response.msg || '返回格式错误'));
}
},
/** 封面上传前校验 */
beforeImageUpload(file) {
this.isUploading = true;
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.isUploading = false;
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.isUploading = false;
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: "0",
modifyTime: null,
deptId: null
};
this.resetForm("form");
if (this.editor) {
this.editor.txt.clear();
}
this.isUploading = false;
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加瑜伽传承";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids[0];
if (!id) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getInherit(id).then(response => {
this.form = { ...response.data };
this.form.status = String(this.form.status || "0");
//
this.$nextTick(() => {
setTimeout(() => {
if (this.editor && this.form.content) {
const processedHtml = this.form.content.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.editor.txt.html(processedHtml);
}
}, 500);
});
this.open = true;
this.title = "修改瑜伽传承";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交按钮 */
submitForm() {
//
if (this.editor) {
const html = this.editor.txt.html();
//
if (html.includes('<img') && html.includes('src=""')) {
this.$message.error('存在无效图片,请重新上传');
return;
}
this.form.content = html;
}
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateInherit(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("修改失败");
});
} else {
addInherit(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("新增失败");
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
if (!ids || (Array.isArray(ids) && ids.length === 0)) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm('是否确认删除瑜伽传承编号为"' + ids + '"的数据项?').then(function() {
return delInherit(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/inherit/export', {
...this.queryParams
}, `inherit_${new Date().getTime()}.xlsx`)
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
}
},
beforeDestroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
};
</script>
<style scoped>
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
/* 图片上传样式 */
.image-uploader {
position: relative;
display: inline-block;
}
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 4px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 150px;
height: 100px;
line-height: 100px;
text-align: center;
}
/* 图片错误样式 */
.image-error {
width: 150px;
height: 100px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
color: #8c939d;
}
</style>

@ -0,0 +1,730 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="不展示" value="0"></el-option>
<el-option label="展示" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:inherit:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:inherit:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="inheritList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" align="center" prop="id" />
<!-- <el-table-column label="门店/校区id" align="center" prop="deptId" >-->
<!-- <template v-for="item in scope.row.deptId">-->
<!-- &lt;!&ndash; <span></span>&ndash;&gt;-->
<!-- <el-tag type="sucess" v-if="item!=''" style="float: left">{{ memberFormat(item) }}</el-tag>-->
<!-- &lt;!&ndash; <span>{{ item }}</span>&ndash;&gt;-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- 门店/校区名称标签形式 -->
<el-table-column label="门店/校区名称" align="center">
<template #default="scope">
<!-- 调用方法获取名称用span或el-tag展示 -->
<el-tag type="info">{{ getDeptName(scope.row.deptId) }}</el-tag>
<!-- 若不需要样式直接用span<span>{{ getDeptName(scope.row.deptId) }}</span> -->
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="封面" align="center" prop="image" width="100">
<template slot-scope="scope">
<el-image
:src="getFullImgUrl(scope.row.image)"
:preview-src-list="[getFullImgUrl(scope.row.image)]"
style="width: 50px; height: 50px;"
fit="cover"
:lazy="false"
></el-image>
</template>
</el-table-column>
<el-table-column label="阅读量" align="center" prop="readNum" />
<el-table-column label="内容" align="center" prop="content" width="120">
<template slot-scope="scope">
<el-button
type="text"
@click="showContentDialog(scope.row.content)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="是否展示" align="center" prop="status" width="120">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? '展示' : '不展示' }}
</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="创建时间" align="center" prop="startTime" width="180">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="更新时间" align="center" prop="modifyTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.modifyTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改瑜伽传承对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 标题表单项后添加 -->
<el-form-item label="门店/校区" prop="deptId">
<el-select
v-model="form.deptId"
placeholder="请选择门店/校区"
clearable
style="width: 100%"
>
<!-- 遍历deptList渲染选项deptId为值deptName为显示文本 -->
<el-option
v-for="dept in deptList"
:key="dept.deptId"
:label="dept.deptName"
:value="dept.deptId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入标题" />
</el-form-item>
<!-- 封面上传区域 -->
<el-form-item label="封面" prop="image">
<el-upload
class="image-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload"
:headers="uploadHeaders"
:disabled="isUploading"
>
<el-image
v-if="form.image"
:src="getFullImgUrl(form.image)"
style="width: 150px; height: 100px;"
fit="cover"
:lazy="false"
>
<div slot="error" class="image-error">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<i v-else class="el-icon-plus image-uploader-icon"></i>
<el-loading
v-if="isUploading"
text="上传中..."
target=".image-uploader"
background="rgba(255,255,255,0.8)"
></el-loading>
</el-upload>
</el-form-item>
<el-form-item label="阅读量" prop="readNum">
<el-input v-model.number="form.readNum" placeholder="请输入阅读量" />
</el-form-item>
<el-form-item label="内容" prop="content">
<div class="editor-container">
<div ref="editor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
<el-form-item label="是否展示" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="0">不展示</el-radio>
<el-radio label="1">展示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 内容查看对话框 -->
<el-dialog
title="内容详情"
:visible.sync="contentDialogVisible"
width="800px"
:before-close="handleDialogClose"
>
<div v-html="contentDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import {getInheritBase} from "@/api/columns/inherit";
import { listMoments, getMoments, delMoments, addMoments, updateMoments } from "@/api/columns/moments";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Practice",
components: {
Pagination,
RightToolbar
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
inheritList: [],
deptList:[],
//
title: "",
//
open: false,
//
contentDialogVisible: false,
contentDialogContent: "",
//
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
//
editor: null,
//
queryParams: {
pageNum: 1,
pageSize: 10,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: null,
modifyTime: null,
deptId: null,
},
//
form: {
status: "0" //
},
//
rules: {
title: [
{ required: true, message: "请输入标题", trigger: "blur" }
],
image: [
{ required: true, message: "请上传封面图片", trigger: "change" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
]
}
};
},
created() {
this.getList();
this.getBase();
},
methods: {
/** 对话框打开后回调 */
onDialogOpened() {
if (!this.editor) {
this.initEditor();
}
},
getDeptName(deptId) {
if (!deptId) return '未设置';
// deptList
// const dept = this.deptList.find(item => item.deptId === deptId);
// return dept ? dept.deptName : '';
for(let e of this.deptList){
if(deptId==e.deptId){
return deptId ? e.deptName : '未知部门';
}
}
},
/** 初始化富文本编辑器 */
initEditor() {
if (this.$refs.editor) {
this.editor = new WangEditor(this.$refs.editor);
//
this.editor.config.showLinkImg = false;
//
this.editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.content = this.editor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('富文本图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.editor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.content = processedHtml;
};
//
this.editor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.editor.create();
} else {
setTimeout(() => this.initEditor(), 100);
}
},
getBase(){
getInheritBase().then(res=>{
console.log(res)
this.deptList=res.data
})
},
/** 查询瑜伽传承列表 */
getList() {
this.loading = true;
listMoments(this.queryParams).then(response => {
this.inheritList = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 显示内容对话框 */
showContentDialog(content) {
let processedContent = content || '';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.contentDialogContent = processedContent;
this.contentDialogVisible = true;
},
/** 关闭内容对话框 */
handleDialogClose() {
this.contentDialogContent = "";
this.contentDialogVisible = false;
},
/** 处理封面上传成功 */
handleImageSuccess(response) {
this.isUploading = false;
if (response && response.code === 200 && response.data) {
this.form.image = response.data;
this.$nextTick(() => {
this.$message.success('封面上传成功');
});
} else {
this.$message.error('上传失败:' + (response.msg || '返回格式错误'));
}
},
/** 封面上传前校验 */
beforeImageUpload(file) {
this.isUploading = true;
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.isUploading = false;
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.isUploading = false;
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: "0",
modifyTime: null,
deptId: null
};
this.resetForm("form");
if (this.editor) {
this.editor.txt.clear();
}
this.isUploading = false;
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加瑜伽传承";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids[0];
if (!id) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getMoments(id).then(response => {
this.form = { ...response.data };
this.form.status = String(this.form.status || "0");
//
this.$nextTick(() => {
setTimeout(() => {
if (this.editor && this.form.content) {
const processedHtml = this.form.content.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.editor.txt.html(processedHtml);
}
}, 500);
});
this.open = true;
this.title = "修改瑜伽传承";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交按钮 */
submitForm() {
//
if (this.editor) {
const html = this.editor.txt.html();
//
if (html.includes('<img') && html.includes('src=""')) {
this.$message.error('存在无效图片,请重新上传');
return;
}
this.form.content = html;
}
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateMoments(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("修改失败");
});
} else {
addMoments(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("新增失败");
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
if (!ids || (Array.isArray(ids) && ids.length === 0)) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm('是否确认删除瑜伽传承编号为"' + ids + '"的数据项?').then(function() {
return delMoments(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/inherit/export', {
...this.queryParams
}, `inherit_${new Date().getTime()}.xlsx`)
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
}
},
beforeDestroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
};
</script>
<style scoped>
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
/* 图片上传样式 */
.image-uploader {
position: relative;
display: inline-block;
}
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 4px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 150px;
height: 100px;
line-height: 100px;
text-align: center;
}
/* 图片错误样式 */
.image-error {
width: 150px;
height: 100px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
color: #8c939d;
}
</style>

@ -0,0 +1,730 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="不展示" value="0"></el-option>
<el-option label="展示" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:inherit:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:inherit:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="inheritList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" align="center" prop="id" />
<!-- <el-table-column label="门店/校区id" align="center" prop="deptId" >-->
<!-- <template v-for="item in scope.row.deptId">-->
<!-- &lt;!&ndash; <span></span>&ndash;&gt;-->
<!-- <el-tag type="sucess" v-if="item!=''" style="float: left">{{ memberFormat(item) }}</el-tag>-->
<!-- &lt;!&ndash; <span>{{ item }}</span>&ndash;&gt;-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- 门店/校区名称标签形式 -->
<el-table-column label="门店/校区名称" align="center">
<template #default="scope">
<!-- 调用方法获取名称用span或el-tag展示 -->
<el-tag type="info">{{ getDeptName(scope.row.deptId) }}</el-tag>
<!-- 若不需要样式直接用span<span>{{ getDeptName(scope.row.deptId) }}</span> -->
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="封面" align="center" prop="image" width="100">
<template slot-scope="scope">
<el-image
:src="getFullImgUrl(scope.row.image)"
:preview-src-list="[getFullImgUrl(scope.row.image)]"
style="width: 50px; height: 50px;"
fit="cover"
:lazy="false"
></el-image>
</template>
</el-table-column>
<el-table-column label="阅读量" align="center" prop="readNum" />
<el-table-column label="内容" align="center" prop="content" width="120">
<template slot-scope="scope">
<el-button
type="text"
@click="showContentDialog(scope.row.content)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="是否展示" align="center" prop="status" width="120">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? '展示' : '不展示' }}
</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="创建时间" align="center" prop="startTime" width="180">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="更新时间" align="center" prop="modifyTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.modifyTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:inherit:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:inherit:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改瑜伽传承对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<!-- 标题表单项后添加 -->
<el-form-item label="门店/校区" prop="deptId">
<el-select
v-model="form.deptId"
placeholder="请选择门店/校区"
clearable
style="width: 100%"
>
<!-- 遍历deptList渲染选项deptId为值deptName为显示文本 -->
<el-option
v-for="dept in deptList"
:key="dept.deptId"
:label="dept.deptName"
:value="dept.deptId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入标题" />
</el-form-item>
<!-- 封面上传区域 -->
<el-form-item label="封面" prop="image">
<el-upload
class="image-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload"
:headers="uploadHeaders"
:disabled="isUploading"
>
<el-image
v-if="form.image"
:src="getFullImgUrl(form.image)"
style="width: 150px; height: 100px;"
fit="cover"
:lazy="false"
>
<div slot="error" class="image-error">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<i v-else class="el-icon-plus image-uploader-icon"></i>
<el-loading
v-if="isUploading"
text="上传中..."
target=".image-uploader"
background="rgba(255,255,255,0.8)"
></el-loading>
</el-upload>
</el-form-item>
<el-form-item label="阅读量" prop="readNum">
<el-input v-model.number="form.readNum" placeholder="请输入阅读量" />
</el-form-item>
<el-form-item label="内容" prop="content">
<div class="editor-container">
<div ref="editor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
<el-form-item label="是否展示" prop="status">
<el-radio-group v-model="form.status">
<el-radio label="0">不展示</el-radio>
<el-radio label="1">展示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 内容查看对话框 -->
<el-dialog
title="内容详情"
:visible.sync="contentDialogVisible"
width="800px"
:before-close="handleDialogClose"
>
<div v-html="contentDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import {getInheritBase} from "@/api/columns/inherit";
import { listSense, getSense, delSense, addSense, updateSense } from "@/api/columns/sense";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Practice",
components: {
Pagination,
RightToolbar
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
inheritList: [],
deptList:[],
//
title: "",
//
open: false,
//
contentDialogVisible: false,
contentDialogContent: "",
//
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
//
editor: null,
//
queryParams: {
pageNum: 1,
pageSize: 10,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: null,
modifyTime: null,
deptId: null,
},
//
form: {
status: "0" //
},
//
rules: {
title: [
{ required: true, message: "请输入标题", trigger: "blur" }
],
image: [
{ required: true, message: "请上传封面图片", trigger: "change" }
],
status: [
{ required: true, message: "请选择状态", trigger: "change" }
]
}
};
},
created() {
this.getList();
this.getBase();
},
methods: {
/** 对话框打开后回调 */
onDialogOpened() {
if (!this.editor) {
this.initEditor();
}
},
getDeptName(deptId) {
if (!deptId) return '未设置';
// deptList
// const dept = this.deptList.find(item => item.deptId === deptId);
// return dept ? dept.deptName : '';
for(let e of this.deptList){
if(deptId==e.deptId){
return deptId ? e.deptName : '未知部门';
}
}
},
/** 初始化富文本编辑器 */
initEditor() {
if (this.$refs.editor) {
this.editor = new WangEditor(this.$refs.editor);
//
this.editor.config.showLinkImg = false;
//
this.editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.content = this.editor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('富文本图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.editor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.content = processedHtml;
};
//
this.editor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.editor.create();
} else {
setTimeout(() => this.initEditor(), 100);
}
},
getBase(){
getInheritBase().then(res=>{
console.log(res)
this.deptList=res.data
})
},
/** 查询瑜伽传承列表 */
getList() {
this.loading = true;
listSense(this.queryParams).then(response => {
this.inheritList = response.rows;
this.total = response.total;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 显示内容对话框 */
showContentDialog(content) {
let processedContent = content || '';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.contentDialogContent = processedContent;
this.contentDialogVisible = true;
},
/** 关闭内容对话框 */
handleDialogClose() {
this.contentDialogContent = "";
this.contentDialogVisible = false;
},
/** 处理封面上传成功 */
handleImageSuccess(response) {
this.isUploading = false;
if (response && response.code === 200 && response.data) {
this.form.image = response.data;
this.$nextTick(() => {
this.$message.success('封面上传成功');
});
} else {
this.$message.error('上传失败:' + (response.msg || '返回格式错误'));
}
},
/** 封面上传前校验 */
beforeImageUpload(file) {
this.isUploading = true;
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.isUploading = false;
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.isUploading = false;
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: null,
title: null,
image: null,
readNum: null,
startTime: null,
content: null,
status: "0",
modifyTime: null,
deptId: null
};
this.resetForm("form");
if (this.editor) {
this.editor.txt.clear();
}
this.isUploading = false;
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加瑜伽传承";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids[0];
if (!id) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getSense(id).then(response => {
this.form = { ...response.data };
this.form.status = String(this.form.status || "0");
//
this.$nextTick(() => {
setTimeout(() => {
if (this.editor && this.form.content) {
const processedHtml = this.form.content.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.editor.txt.html(processedHtml);
}
}, 500);
});
this.open = true;
this.title = "修改瑜伽传承";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交按钮 */
submitForm() {
//
if (this.editor) {
const html = this.editor.txt.html();
//
if (html.includes('<img') && html.includes('src=""')) {
this.$message.error('存在无效图片,请重新上传');
return;
}
this.form.content = html;
}
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateSense(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("修改失败");
});
} else {
addSense(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("新增失败");
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
if (!ids || (Array.isArray(ids) && ids.length === 0)) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm('是否确认删除瑜伽传承编号为"' + ids + '"的数据项?').then(function() {
return delSense(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/inherit/export', {
...this.queryParams
}, `inherit_${new Date().getTime()}.xlsx`)
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
}
},
beforeDestroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
};
</script>
<style scoped>
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
/* 图片上传样式 */
.image-uploader {
position: relative;
display: inline-block;
}
.image-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 4px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader .el-upload:hover {
border-color: #409EFF;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 150px;
height: 100px;
line-height: 100px;
text-align: center;
}
/* 图片错误样式 */
.image-error {
width: 150px;
height: 100px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
color: #8c939d;
}
</style>

@ -0,0 +1,822 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<!-- <el-form-item label="门店图片" prop="banner">-->
<!-- <el-input-->
<!-- v-model="queryParams.banner"-->
<!-- placeholder="请输入门店图片标识"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="门店名称" prop="storeName">
<el-input
v-model="queryParams.storeName"
placeholder="请输入门店名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input
v-model="queryParams.address"
placeholder="请输入地址"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="门店电话" prop="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入门店电话"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="primary"-->
<!-- plain-->
<!-- icon="el-icon-plus"-->
<!-- size="mini"-->
<!-- @click="handleAdd"-->
<!-- v-hasPermi="['system:store:add']"-->
<!-- >新增</el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="success"-->
<!-- plain-->
<!-- icon="el-icon-edit"-->
<!-- size="mini"-->
<!-- :disabled="single"-->
<!-- @click="handleUpdate"-->
<!-- v-hasPermi="['system:store:edit']"-->
<!-- >修改</el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="danger"-->
<!-- plain-->
<!-- icon="el-icon-delete"-->
<!-- size="mini"-->
<!-- :disabled="multiple"-->
<!-- @click="handleDelete"-->
<!-- v-hasPermi="['system:store:remove']"-->
<!-- >删除</el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="warning"-->
<!-- plain-->
<!-- icon="el-icon-download"-->
<!-- size="mini"-->
<!-- @click="handleExport"-->
<!-- v-hasPermi="['system:store:export']"-->
<!-- >导出</el-button>-->
<!-- </el-col>-->
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="storeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="门店图片" align="center" prop="banner" width="220">
<template slot-scope="scope">
<div v-if="scope.row.banner" class="album-images">
<el-image
v-for="(img, index) in splitImages(scope.row.banner).slice(0, 3)"
:key="index"
:src="getFullImgUrl(img)"
:preview-src-list="splitImages(scope.row.banner).map(item => getFullImgUrl(item))"
class="album-img"
fit="cover"
:lazy="false"
></el-image>
<span v-if="splitImages(scope.row.banner).length > 3" class="more-count">
+{{ splitImages(scope.row.banner).length - 3 }}
</span>
</div>
<span v-else class="no-image">无图片</span>
</template>
</el-table-column>
<el-table-column label="门店名称" align="center" prop="storeName" />
<el-table-column label="地址" align="center" prop="address" />
<el-table-column label="门店电话" align="center" prop="phone" />
<el-table-column label="创始人/店长简介" align="center" prop="founder">
<template slot-scope="scope">
<el-button
type="text"
@click="showFounderDialog(scope.row.founder)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="企业/门店简介" align="center" prop="profile">
<template slot-scope="scope">
<el-button
type="text"
@click="showProfileDialog(scope.row.profile)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="部门ID" align="center" prop="deptName" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:store:edit']"
>修改</el-button>
<!-- <el-button-->
<!-- size="mini"-->
<!-- type="text"-->
<!-- icon="el-icon-delete"-->
<!-- @click="handleDelete(scope.row)"-->
<!-- v-hasPermi="['system:store:remove']"-->
<!-- >删除</el-button>-->
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改门店对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="门店图片" prop="banner">
<el-upload
:action="uploadImgUrl"
list-type="picture-card"
:file-list="albumFileList"
:on-success="handleAlbumSuccess"
:on-remove="handleAlbumRemove"
:limit="6"
:on-exceed="handleExceed"
:before-upload="beforeAlbumUpload"
:headers="uploadHeaders"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">
支持JPG/PNG格式单张不超过2MB最多上传6张
</div>
</el-upload>
</el-form-item>
<el-form-item label="门店名称" prop="storeName">
<el-input v-model="form.storeName" placeholder="请输入门店名称" />
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="form.address" placeholder="请输入地址" />
</el-form-item>
<el-form-item label="门店电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入门店电话" />
</el-form-item>
<!-- 创始人/店长简介 - 富文本编辑器 -->
<el-form-item label="创始人/店长简介" prop="founder">
<div class="editor-container founder-editor">
<div ref="founderEditor" style="width: 100%; min-height: 200px;"></div>
</div>
</el-form-item>
<!-- 企业/门店简介 - 富文本编辑器 -->
<el-form-item label="企业/门店简介" prop="profile">
<div class="editor-container profile-editor">
<div ref="profileEditor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 创始人简介查看对话框 -->
<el-dialog
title="创始人/店长简介"
:visible.sync="founderDialogVisible"
width="600px"
:before-close="handleFounderDialogClose"
>
<div v-html="founderDialogContent" class="content-viewer"></div>
</el-dialog>
<!-- 门店简介查看对话框 -->
<el-dialog
title="企业/门店简介"
:visible.sync="profileDialogVisible"
width="800px"
:before-close="handleProfileDialogClose"
>
<div v-html="profileDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import { listStore, getStore, delStore, addStore, updateStore } from "@/api/columns/store";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Store",
components: {
Pagination,
RightToolbar
},
data() {
return {
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
storeList: [],
//
title: "",
//
open: false,
//
founderDialogVisible: false,
founderDialogContent: "",
//
profileDialogVisible: false,
profileDialogContent: "",
//
founderEditor: null,
profileEditor: null,
//
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
albumFileList: [],
//
queryParams: {
pageNum: 1,
pageSize: 10,
banner: null,
storeName: null,
address: null,
phone: null,
founder: null,
profile: null,
},
//
form: {},
//
rules: {
storeName: [
{ required: true, message: "门店名称不能为空", trigger: "blur" }
],
phone: [
{ required: true, message: "门店电话不能为空", trigger: "blur" }
],
address: [
{ required: true, message: "门店地址不能为空", trigger: "blur" }
]
}
};
},
created() {
this.getList();
},
methods: {
/** 对话框打开后初始化富文本编辑器 */
onDialogOpened() {
if (!this.founderEditor) {
this.initFounderEditor();
}
if (!this.profileEditor) {
this.initProfileEditor();
}
},
/** 初始化创始人/店长简介富文本编辑器 */
initFounderEditor() {
if (this.$refs.founderEditor) {
this.founderEditor = new WangEditor(this.$refs.founderEditor);
//
this.founderEditor.config.showLinkImg = false;
//
this.founderEditor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.founder = this.founderEditor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('创始人简介图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.founderEditor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.founder = processedHtml;
};
//
this.founderEditor.config.menus = [
'head', 'bold', 'fontSize', 'foreColor', 'backColor',
'link', 'list', 'justify', 'quote', 'image', 'undo', 'redo'
];
//
this.founderEditor.create();
} else {
setTimeout(() => this.initFounderEditor(), 100);
}
},
/** 初始化企业/门店简介富文本编辑器 */
initProfileEditor() {
if (this.$refs.profileEditor) {
this.profileEditor = new WangEditor(this.$refs.profileEditor);
//
this.profileEditor.config.showLinkImg = false;
//
this.profileEditor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.profile = this.profileEditor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('门店简介图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.profileEditor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.profile = processedHtml;
};
//
this.profileEditor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.profileEditor.create();
} else {
setTimeout(() => this.initProfileEditor(), 100);
}
},
/** 查询门店列表 */
getList() {
this.loading = true;
listStore(this.queryParams).then(response => {
this.storeList = response.rows || [];
this.total = response.total || 0;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 显示创始人简介对话框 */
showFounderDialog(content) {
let processedContent = content || '暂无简介';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.founderDialogContent = processedContent;
this.founderDialogVisible = true;
},
/** 关闭创始人简介对话框 */
handleFounderDialogClose() {
this.founderDialogContent = "";
this.founderDialogVisible = false;
},
/** 显示门店简介对话框 */
showProfileDialog(content) {
let processedContent = content || '暂无简介';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.profileDialogContent = processedContent;
this.profileDialogVisible = true;
},
/** 关闭门店简介对话框 */
handleProfileDialogClose() {
this.profileDialogContent = "";
this.profileDialogVisible = false;
},
/** 分割图片URL */
splitImages(urlStr) {
if (!urlStr || typeof urlStr !== 'string') return [];
return urlStr.split(',').filter(img => img && img.trim());
},
/** 处理相册上传成功 */
handleAlbumSuccess(response, file, fileList) {
if (response.code === 200) {
file.url = this.getFullImgUrl(response.data);
this.form.banner = fileList.map(f => f.url.replace(this.baseUrl, '')).join(',');
} else {
this.$message.error('上传失败:' + response.msg);
}
},
/** 相册图片删除 */
handleAlbumRemove(file, fileList) {
this.form.banner = fileList.map(f => f.url.replace(this.baseUrl, '')).join(',');
},
/** 上传数量超限 */
handleExceed(files, fileList) {
this.$message.warning(`最多只能上传6张图片`);
},
/** 相册上传前校验 */
beforeAlbumUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
banner: null,
storeName: null,
address: null,
phone: null,
founder: null,
profile: null,
deptId: null
};
this.resetForm("form");
//
if (this.founderEditor) {
this.founderEditor.txt.clear();
}
if (this.profileEditor) {
this.profileEditor.txt.clear();
}
this.albumFileList = [];
this.isUploading = false;
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.deptId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加门店";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const deptId = row?.deptId || (this.ids.length > 0 ? this.ids[0] : null);
if (!deptId) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getStore(deptId).then(response => {
this.form = { ...response.data };
// -
this.$nextTick(() => {
setTimeout(() => {
if (this.founderEditor && this.form.founder) {
const processedHtml = this.form.founder.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.founderEditor.txt.html(processedHtml);
}
}, 500);
});
// -
this.$nextTick(() => {
setTimeout(() => {
if (this.profileEditor && this.form.profile) {
const processedHtml = this.form.profile.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.profileEditor.txt.html(processedHtml);
}
}, 500);
});
//
if (this.form.banner) {
this.albumFileList = this.splitImages(this.form.banner).map(url => ({
url: this.getFullImgUrl(url),
name: 'store-img',
status: 'success'
}));
}
this.open = true;
this.title = "修改门店";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交按钮 */
submitForm() {
//
if (this.founderEditor) {
const founderHtml = this.founderEditor.txt.html();
//
if (founderHtml.includes('<img') && founderHtml.includes('src=""')) {
this.$message.error('创始人简介中存在无效图片,请重新上传');
return;
}
this.form.founder = founderHtml;
}
if (this.profileEditor) {
const profileHtml = this.profileEditor.txt.html();
//
if (profileHtml.includes('<img') && profileHtml.includes('src=""')) {
this.$message.error('门店简介中存在无效图片,请重新上传');
return;
}
this.form.profile = profileHtml;
}
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.deptId != null) {
updateStore(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("修改失败");
});
} else {
addStore(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError("新增失败");
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const deptIds = row?.deptId || this.ids;
if (!deptIds || (Array.isArray(deptIds) && deptIds.length === 0)) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm(`是否确认删除选中的门店信息?`).then(() => {
return delStore(deptIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/store/export', {
...this.queryParams
}, `store_${new Date().getTime()}.xlsx`)
}
},
beforeDestroy() {
//
if (this.founderEditor) {
this.founderEditor.destroy();
this.founderEditor = null;
}
if (this.profileEditor) {
this.profileEditor.destroy();
this.profileEditor = null;
}
}
};
</script>
<style scoped>
/* 相册样式 */
.album-images {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.album-img {
width: 60px;
height: 60px;
border-radius: 4px;
cursor: pointer;
}
.more-count {
width: 60px;
height: 60px;
background: #f5f5f5;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
border: 1px solid #eee;
}
.no-image {
color: #999;
font-size: 14px;
}
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
margin-bottom: 10px;
}
.founder-editor {
min-height: 200px;
}
.profile-editor {
min-height: 300px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
</style>

@ -0,0 +1,792 @@
<template>
<div class="app-container">
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="老师名称" prop="teacherName">
<el-input
v-model="queryParams.teacherName"
placeholder="请输入老师名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="教练风采状态" prop="releases">
<el-select
v-model="queryParams.releases"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="不展示" value="0"></el-option>
<el-option label="展示" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<!-- 操作按钮区域 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:teacher:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:teacher:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:teacher:remove']"
>删除</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 表格区域 -->
<el-table v-loading="loading" :data="teacherList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="员工id" align="center" prop="userId" width="80" />
<el-table-column label="老师名称" align="center" prop="teacherName" />
<el-table-column label="头像" align="center" prop="avatarImg" width="100">
<template slot-scope="scope">
<el-image
:src="getFullImgUrl(scope.row.avatarImg)"
:preview-src-list="[getFullImgUrl(scope.row.avatarImg)]"
style="width: 60px; height: 60px; border-radius: 50%;"
fit="cover"
:lazy="false"
></el-image>
</template>
</el-table-column>
<el-table-column label="教练风采内容" align="center" prop="context" width="120">
<template slot-scope="scope">
<el-button
type="text"
@click="showContentDialog(scope.row.context)"
size="mini"
>查看内容</el-button>
</template>
</el-table-column>
<el-table-column label="教练风采相册" align="center" prop="url" width="220">
<template slot-scope="scope">
<div v-if="scope.row.url" class="album-images">
<el-image
v-for="(img, index) in splitImages(scope.row.url).slice(0, 3)"
:key="index"
:src="getFullImgUrl(img)"
:preview-src-list="splitImages(scope.row.url).map(item => getFullImgUrl(item))"
class="album-img"
fit="cover"
:lazy="false"
></el-image>
<span v-if="splitImages(scope.row.url).length > 3" class="more-count">
+{{ splitImages(scope.row.url).length - 3 }}
</span>
</div>
<span v-else class="no-image">无图片</span>
</template>
</el-table-column>
<el-table-column label="教练风采状态" align="center" prop="releases" width="120">
<template slot-scope="scope">
<el-tag :type="scope.row.releases === 1 ? 'success' : 'info'">
{{ scope.row.releases === 1 ? '展示' : '不展示' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="140">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:teacher:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:teacher:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="onDialogOpened">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="员工姓名" prop="userId">
<el-select
v-model="form.userId"
placeholder="请选择员工"
clearable
filterable
style="width: 100%"
>
<el-option
v-for="emp in employeeList"
:key="emp.userId"
:label="emp.nickName"
:value="emp.userId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="老师名称" prop="teacherName">
<el-input v-model="form.teacherName" placeholder="请输入老师名称" />
</el-form-item>
<!-- 头像上传区域 -->
<el-form-item label="头像" prop="avatarImg">
<el-upload
class="avatar-uploader"
:action="uploadImgUrl"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:headers="uploadHeaders"
:disabled="isUploading"
>
<el-image
v-if="form.avatarImg"
:src="getFullImgUrl(form.avatarImg)"
style="width: 100px; height: 100px; border-radius: 50%;"
fit="cover"
:lazy="false"
>
<div slot="error" class="image-error">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
<el-loading
v-if="isUploading"
text="上传中..."
target=".avatar-uploader"
background="rgba(255,255,255,0.8)"
></el-loading>
</el-upload>
</el-form-item>
<el-form-item label="教练风采内容" prop="context">
<div class="editor-container">
<div ref="editor" style="width: 100%; min-height: 300px;"></div>
</div>
</el-form-item>
<el-form-item label="教练风采相册" prop="url">
<el-upload
:action="uploadImgUrl"
list-type="picture-card"
:file-list="albumFileList"
:on-success="handleAlbumSuccess"
:on-remove="handleAlbumRemove"
:limit="6"
:on-exceed="handleExceed"
:before-upload="beforeAlbumUpload"
:headers="uploadHeaders"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">
支持JPG/PNG格式单张不超过2MB最多上传6张
</div>
</el-upload>
</el-form-item>
<el-form-item label="教练风采状态" prop="releases">
<el-radio-group v-model="form.releases">
<el-radio label="0">不展示</el-radio>
<el-radio label="1">展示</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 内容查看对话框 -->
<el-dialog
title="教练风采内容"
:visible.sync="contentDialogVisible"
width="800px"
:before-close="handleDialogClose"
>
<div v-html="contentDialogContent" class="content-viewer"></div>
</el-dialog>
</div>
</template>
<script>
import { listTeacher, getTeacher, delTeacher, addTeacher, updateTeacher } from "@/api/columns/teacher";
import { listAll } from "@/api/system/user";
import WangEditor from 'wangeditor';
import { getToken } from '@/utils/auth';
import axios from 'axios';
import Pagination from '@/components/Pagination';
import RightToolbar from '@/components/RightToolbar';
export default {
name: "Teacher",
components: {
Pagination,
RightToolbar
},
data() {
return {
loading: true,
ids: [],
single: true,
multiple: true,
showSearch: true,
total: 0,
teacherList: [],
employeeList: [],
title: "",
open: false,
contentDialogVisible: false,
contentDialogContent: "",
uploadHeaders: {
Authorization: getToken()
},
uploadImgUrl: process.env.VUE_APP_BASE_API + "/com/file/upload",
isUploading: false,
baseUrl: process.env.VUE_APP_BASE_API || '',
queryParams: {
pageNum: 1,
pageSize: 10,
teacherName: null,
releases: null,
},
form: {
releases: "0"
},
editor: null,
albumFileList: [],
rules: {
userId: [
{ required: true, message: "请选择员工", trigger: "change" }
],
teacherName: [
{ required: true, message: "老师名称不能为空", trigger: "blur" }
],
releases: [
{ required: true, message: "请选择状态", trigger: "change" }
]
}
};
},
created() {
this.getList();
this.getBase();
},
methods: {
/** 对话框打开后回调 */
onDialogOpened() {
if (!this.editor) {
this.initEditor();
}
},
/** 初始化富文本编辑器 */
initEditor() {
console.log(11)
console.log("初始化富文本")
if (this.$refs.editor) {
this.editor = new WangEditor(this.$refs.editor);
//
this.editor.config.showLinkImg = false;
//
this.editor.config.customUploadImg = async (resultFiles, insertImgFn) => {
this.isUploading = true;
try {
for (const file of resultFiles) {
const formData = new FormData();
formData.append('file', file);
const response = await axios({
url: this.uploadImgUrl,
method: 'post',
data: formData,
headers: {
...this.uploadHeaders,
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
if (response.data && response.data.code === 200 && response.data.data) {
//
const relativeUrl = response.data.data;
const fullUrl = this.getFullImgUrl(relativeUrl);
//
insertImgFn(fullUrl, file.name || '图片', 'max-width:100%;height:auto;');
//
this.form.context = this.editor.txt.html();
this.$message.success('图片上传成功');
} else {
this.$message.error('图片上传失败: ' + (response.data?.msg || '服务器返回异常'));
}
}
} catch (error) {
console.error('富文本图片上传错误:', error);
this.$message.error('上传失败,请检查网络或联系管理员');
} finally {
this.isUploading = false;
}
};
//
this.editor.config.onchange = (html) => {
const processedHtml = html.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
this.form.context = processedHtml;
console.log(this.form.context)
};
//
this.editor.config.menus = [
'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
'justify', 'quote', 'emoticon', 'image', 'table', 'undo', 'redo'
];
//
this.editor.create();
} else {
setTimeout(() => this.initEditor(), 100);
}
},
/** 查询列表 */
getList() {
this.loading = true;
listTeacher(this.queryParams).then(response => {
this.teacherList = response.rows || [];
this.total = response.total || 0;
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取列表数据失败');
});
},
/** 获取员工列表 */
getBase() {
this.loading = true;
listAll().then(res => {
this.employeeList = res.rows || [];
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('获取员工列表失败');
});
},
/** 显示内容对话框 */
showContentDialog(content) {
let processedContent = content || '';
processedContent = processedContent.replace(
/<img/g,
'<img style="max-width:100%;height:auto;margin:10px auto;display:block;"'
);
this.contentDialogContent = processedContent;
this.contentDialogVisible = true;
},
/** 关闭内容对话框 */
handleDialogClose() {
this.contentDialogContent = "";
this.contentDialogVisible = false;
},
/** 分割图片URL */
splitImages(urlStr) {
if (!urlStr || typeof urlStr !== 'string') return [];
return urlStr.split(',').filter(img => img && img.trim());
},
/** 处理头像上传成功 */
handleAvatarSuccess(response) {
this.isUploading = false;
if (response && response.code === 200 && response.data) {
this.form.avatarImg = response.data;
this.$nextTick(() => {
this.$message.success('头像上传成功');
});
} else {
this.$message.error('上传失败:' + (response.msg || '返回格式错误'));
}
},
/** 头像上传前校验 */
beforeAvatarUpload(file) {
this.isUploading = true;
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.isUploading = false;
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.isUploading = false;
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
/** 处理相册上传成功 */
handleAlbumSuccess(response, file, fileList) {
if (response.code === 200) {
file.url = this.getFullImgUrl(response.data);
this.form.url = fileList.map(f => f.url.replace(this.baseUrl, '')).join(',');
} else {
this.$message.error('上传失败:' + response.msg);
}
},
/** 相册图片删除 */
handleAlbumRemove(file, fileList) {
this.form.url = fileList.map(f => f.url.replace(this.baseUrl, '')).join(',');
},
/** 上传数量超限 */
handleExceed(files, fileList) {
this.$message.warning(`最多只能上传6张图片`);
},
/** 相册上传前校验 */
beforeAlbumUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('只能上传JPG/PNG格式的图片');
return false;
}
if (!isLt2M) {
this.$message.error('图片大小不能超过2MB');
return false;
}
return true;
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
userId: null,
teacherName: null,
avatarImg: null,
context: null,
url: null,
releases: "0"
};
this.resetForm("form");
if (this.editor) {
this.editor.txt.clear();
}
this.albumFileList = [];
this.isUploading = false;
},
/** 搜索 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置搜索 */
resetQuery() {
this.$refs.queryForm.resetFields();
this.handleQuery();
},
/** 选择变化 */
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
console.log(this.ids);
},
/** 新增 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加教练信息";
},
/** 修改 */
handleUpdate(row) {
this.reset();
const userId = row?.userId || this.ids[0];
if (!userId) {
this.$message.warning('请选择一条记录进行修改');
return;
}
getTeacher(userId).then(response => {
this.form = { ...response.data };
this.form.releases = String(this.form.releases || "0");
// -
// if (this.editor && this.form.context) {
// let processedHtml = this.form.context;
// //
// processedHtml = processedHtml.replace(/<img src=""/g, `<img src="${this.baseUrl}/"`);
// processedHtml = processedHtml.replace(/<img/g, '<img style="max-width:100%;height:auto;"');
// this.editor.txt.html(processedHtml);
// this.form.context = processedHtml; //
// console.log(1)
// console.log(this.form.context)
//
// }
this.$nextTick(() => {
setTimeout(() => {
if (this.editor && this.form.context) {
const processedHtml = this.form.context.replace(
/<img/g,
'<img style="max-width:100%;height:auto;"'
);
this.editor.txt.html(processedHtml);
}
}, 500); // editor
});
// this.form.context = this.form.context || '' //
//
if (this.form.url) {
this.albumFileList = this.splitImages(this.form.url).map(url => ({
url: this.getFullImgUrl(url),
name: 'album-img',
status: 'success'
}));
}
this.$nextTick(() => {
this.form.avatarImg = this.form.avatarImg;
});
this.open = true;
this.title = "修改教练信息";
}).catch(() => {
this.$message.error('获取数据失败');
});
},
/** 提交表单 */
submitForm() {
//
if (this.editor) {
console.log(this.form.context);
const html = this.editor.txt.html();
console.log(html);
//
if (html.includes('<img') && html.includes('src=""')) {
this.$message.error('存在无效图片,请重新上传');
return;
}
this.form.context = html;
}
this.$refs["form"].validate(valid => {
if (valid) {
const submitFunc = this.title !== '添加教练信息' ? updateTeacher : addTeacher;
submitFunc(this.form).then(() => {
this.$modal.msgSuccess(this.form.userId ? "修改成功" : "新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError(this.form.userId ? "修改失败" : "新增失败");
});
}
});
},
handleDelete(row) {
let userIds = [];
if (row && row.userId !== undefined) {
userIds = [row.userId]; // [1]
} else {
userIds = this.ids; // [1,2,3]
}
console.log(row)
console.log(userIds)
console.log(this.ids)
if (userIds.length === 0) {
this.$message.warning('请选择至少一条记录进行删除');
return;
}
this.$modal.confirm(`是否确认删除选中的教练信息?`).then(() => {
// {ids: ...}
console.log(userIds)
return delTeacher(userIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 处理图片URL */
getFullImgUrl(url) {
if (!url || typeof url !== 'string') return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return this.baseUrl + (this.baseUrl.endsWith('/') ? '' : '/') + url;
}
},
beforeDestroy() {
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
};
</script>
<style scoped>
/* 相册样式 */
.album-images {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.album-img {
width: 60px;
height: 60px;
border-radius: 4px;
cursor: pointer;
}
.more-count {
width: 60px;
height: 60px;
background: #f5f5f5;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #666;
border: 1px solid #eee;
}
.no-image {
color: #999;
font-size: 14px;
}
/* 富文本样式 */
.editor-container {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
}
.editor-container img {
max-width: 100% !important;
height: auto !important;
}
/* 查看内容样式 */
.content-viewer {
line-height: 1.8;
word-break: break-all;
padding: 15px;
max-height: 600px;
overflow-y: auto;
}
.content-viewer img {
max-width: 100% !important;
height: auto !important;
margin: 10px auto !important;
display: block !important;
}
/* 头像上传样式 */
.avatar-uploader {
position: relative;
display: inline-block;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 50%;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
/* 图片错误样式 */
.image-error {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
color: #8c939d;
}
</style>
Loading…
Cancel
Save