整合前端

This commit is contained in:
砂糖
2026-04-13 17:04:38 +08:00
parent 69609a2cb1
commit 5d4794c9bd
915 changed files with 144259 additions and 0 deletions

View File

@@ -0,0 +1,518 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="所属文章分类" prop="categoryId">
<el-select v-model="queryParams.categoryId" placeholder="请选择分类" clearable>
<el-option v-for="item in categoryOptions" :key="item.categoryId" :label="item.categoryName"
:value="item.categoryId" />
</el-select>
</el-form-item>
<el-form-item label="语言编码" prop="langCode">
<LanguageSelect v-model="queryParams.langCode" placeholder="请选择语种" />
</el-form-item>
<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="isPublished">
<el-select v-model="queryParams.isPublished" placeholder="请选择发布状态" clearable>
<el-option label="已发布" value="1" />
<el-option label="未发布" value="0" />
</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">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
@click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="articleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="所属文章分类" align="center" min-width="120">
<template slot-scope="scope">
{{ getCategoryName(scope.row.categoryId) }}
</template>
</el-table-column>
<el-table-column label="语言" align="center" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.langCode === 'zh-CN' ? 'primary' : 'success'" size="small">{{ scope.row.langCode
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="封面" align="center" width="80">
<template slot-scope="scope">
<image-preview :src="scope.row.cover" fit="contain" width="60" height="40" />
</template>
</el-table-column>
<el-table-column label="文章标题" prop="title" align="center" min-width="200" show-overflow-tooltip />
<el-table-column label="摘要" prop="summary" align="center" min-width="150" show-overflow-tooltip />
<el-table-column label="发布状态" align="center" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.isPublished === '1' ? 'success' : 'info'" size="small">
{{ scope.row.isPublished === '1' ? '已发布' : '未发布' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="发布时间" align="center" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.publishedTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="关联文章" align="center" width="120">
<template slot-scope="scope">
<el-button v-if="scope.row.relatedArticleId" type="text" size="mini" @click="handleViewRelated(scope.row)">
查看关联
</el-button>
<span v-else></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)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreview(scope.row)">预览</el-button>
<el-button size="mini" type="text" icon="el-icon-link" @click="handleCopyLink(scope.row)">复制链接</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="900px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px" size="small">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="所属文章分类" prop="categoryId" required>
<el-select v-model="form.categoryId" placeholder="请选择分类" clearable>
<el-option v-for="item in categoryOptions" :key="item.categoryId" :label="item.categoryName"
:value="item.categoryId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="语言编码" prop="langCode" required>
<LanguageSelect v-model="form.langCode" placeholder="请选择语种" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="文章标题" prop="title" required>
<el-input v-model="form.title" placeholder="请输入文章标题" maxlength="200" show-word-limit />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="关联文章ID" prop="relatedArticleId">
<el-input v-model="form.relatedArticleId" placeholder="请输入关联文章ID同一篇文章的其他语言版本" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="封面地址" prop="cover">
<el-input v-model="form.cover" placeholder="请输入封面地址" />
</el-form-item>
<el-form-item label="摘要" prop="summary">
<el-input v-model="form.summary" type="textarea" placeholder="请输入摘要" :rows="3" maxlength="500"
show-word-limit />
</el-form-item>
<el-form-item label="文章内容" prop="content" required>
<editor v-model="form.content" :min-height="300" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="发布状态" prop="isPublished">
<el-select v-model="form.isPublished" placeholder="请选择发布状态" clearable>
<el-option label="已发布" value="1" />
<el-option label="未发布" value="0" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发布时间" prop="publishedTime">
<el-date-picker clearable v-model="form.publishedTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择发布时间" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="SEO 友好链接" prop="slug">
<el-input v-model="form.slug" placeholder="请输入SEO 友好链接" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input-number v-model="form.sortOrder" :min="0" :max="9999" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel"> </el-button>
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
</div>
</el-dialog>
<!-- 文章预览对话框 -->
<el-dialog title="文章预览" :visible.sync="previewDialog" width="80%" top="5vh">
<div class="preview-container">
<h3 class="preview-title">{{ previewTitle }}</h3>
<div class="preview-meta">
<span class="meta-item">{{ parseTime(previewPublishedTime, '{y}-{m}-{d} {h}:{i}') }}</span>
<span class="meta-item">{{ previewLangCode }}</span>
</div>
<div v-html="previewContent" class="preview-content"></div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="previewDialog = false">关闭</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { addArticle, delArticle, getArticle, listArticle, updateArticle } from "@/api/site/article";
import { listArticleCategory } from "@/api/site/articleCategory";
import LanguageSelect from '@/components/LanguageSelect.vue';
export default {
name: "Article",
components: {
LanguageSelect
},
data () {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 文章表格数据
articleList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
categoryId: undefined,
langCode: undefined,
title: undefined,
isPublished: undefined
},
// 表单参数
form: {
articleId: undefined,
categoryId: undefined,
langCode: undefined,
slug: undefined,
title: undefined,
summary: undefined,
content: undefined,
isPublished: "0",
publishedTime: new Date().toISOString().slice(0, 19).replace('T', ' '),
sortOrder: 0,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
cover: undefined,
relatedArticleId: undefined
},
// 表单校验
rules: {
categoryId: [
{ required: true, message: '请选择所属文章分类', trigger: 'change' }
],
langCode: [
{ required: true, message: '请选择语言编码', trigger: 'change' }
],
title: [
{ required: true, message: '请输入文章标题', trigger: 'blur' },
{ min: 1, max: 200, message: '标题长度不能超过200个字符', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入文章内容', trigger: 'blur' }
]
},
categoryOptions: [],
previewDialog: false,
previewContent: "",
previewTitle: "",
previewPublishedTime: "",
previewLangCode: ""
};
},
created () {
this.getList();
this.getCategoryOptions();
},
methods: {
getCategoryOptions () {
listArticleCategory({}).then(res => {
this.categoryOptions = res.rows || [];
});
},
getCategoryName (id) {
const item = this.categoryOptions.find(opt => opt.categoryId === id);
return item ? item.categoryName : id;
},
handlePreview (row) {
if (row.content) {
this.previewTitle = row.title;
this.previewContent = row.content;
this.previewPublishedTime = row.publishedTime;
this.previewLangCode = row.langCode;
this.previewDialog = true;
} else {
getArticle(row.articleId).then(res => {
this.previewTitle = res.data.title;
this.previewContent = res.data.content;
this.previewPublishedTime = res.data.publishedTime;
this.previewLangCode = res.data.langCode;
this.previewDialog = true;
});
}
},
handleViewRelated (row) {
if (row.relatedArticleId) {
this.loading = true;
getArticle(row.relatedArticleId).then(res => {
this.loading = false;
this.previewTitle = res.data.title;
this.previewContent = res.data.content;
this.previewPublishedTime = res.data.publishedTime;
this.previewLangCode = res.data.langCode;
this.previewDialog = true;
}).catch(() => {
this.loading = false;
this.$message.error('获取关联文章失败');
});
}
},
/** 查询文章列表 */
getList () {
this.loading = true;
listArticle(this.queryParams).then(response => {
this.articleList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel () {
this.open = false;
this.reset();
},
// 表单重置
reset () {
this.form = {
articleId: undefined,
categoryId: undefined,
langCode: undefined,
slug: undefined,
title: undefined,
summary: undefined,
content: undefined,
isPublished: "0",
publishedTime: new Date().toISOString().slice(0, 19).replace('T', ' '),
sortOrder: 0,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
cover: undefined,
relatedArticleId: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery () {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery () {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange (selection) {
this.ids = selection.map(item => item.articleId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd () {
this.reset();
this.open = true;
this.title = "添加文章";
},
/** 修改按钮操作 */
handleUpdate (row) {
this.loading = true;
this.reset();
const articleId = row.articleId || this.ids
getArticle(articleId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改文章";
}).catch(() => {
this.loading = false;
this.$message.error('获取文章详情失败');
});
},
/** 提交按钮 */
submitForm () {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
const articleData = {
...this.form
};
// 处理slug自动生成
if (!articleData.slug && articleData.title) {
articleData.slug = articleData.title.toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-').substring(0, 100);
}
const requestMethod = articleData.articleId ? updateArticle : addArticle;
requestMethod(articleData).then(response => {
this.$modal.msgSuccess(articleData.articleId ? "修改成功" : "新增成功");
this.open = false;
this.getList();
}).catch(() => {
this.$modal.msgError(articleData.articleId ? "修改失败" : "新增失败");
}).finally(() => {
this.buttonLoading = false;
});
}
});
},
/** 删除按钮操作 */
handleDelete (row) {
const articleIds = row.articleId || this.ids;
this.$modal.confirm('是否确认删除选中的文章数据?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.loading = true;
return delArticle(articleIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
this.ids = [];
this.single = true;
this.multiple = true;
}).catch(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport () {
this.download('site/article/export', {
...this.queryParams
}, `article_${new Date().getTime()}.xlsx`)
},
handleCopyLink (row) {
const url = `/${row.categoryId}/${row.articleId}`;
if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(url).then(() => {
this.$message.success('复制成功');
}, () => {
this.$message.error('复制失败,请手动复制');
});
} else {
// 兼容性处理
const input = document.createElement('input');
input.value = url;
document.body.appendChild(input);
input.select();
try {
document.execCommand('copy');
this.$message.success('复制成功');
} catch (e) {
this.$message.error('复制失败,请手动复制');
}
document.body.removeChild(input);
}
},
/** 快速添加关联文章 */
quickAddRelatedArticle () {
if (this.form.articleId) {
this.reset();
this.form.relatedArticleId = this.form.articleId;
this.open = true;
this.title = "添加关联文章(其他语言版本)";
}
}
}
};
</script>
<style scoped>
.preview-container {
padding: 20px;
}
.preview-title {
font-size: 24px;
font-weight: bold;
margin-bottom: 20px;
text-align: center;
}
.preview-meta {
text-align: center;
color: #909399;
margin-bottom: 30px;
font-size: 14px;
}
.meta-item {
margin: 0 10px;
}
.preview-content {
line-height: 1.8;
font-size: 16px;
}
.preview-content img {
max-width: 100%;
height: auto;
margin: 10px 0;
}
</style>

View File

@@ -0,0 +1,257 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="分类描述" prop="description">
<el-input v-model="queryParams.description" placeholder="请输入分类描述" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="queryParams.sortOrder" placeholder="请输入排序" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnabled">
<el-input v-model="queryParams.isEnabled" 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">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
@click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="articleCategoryList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="文章分类主键" align="center" prop="categoryId" v-if="true"/> -->
<!-- <el-table-column label="上级分类ID" align="center" prop="parentId" /> -->
<!-- <el-table-column label="语言编码" align="center" prop="langCode" /> -->
<el-table-column label="分类名称" align="center" prop="categoryName" />
<el-table-column label="分类描述" align="center" prop="description" />
<el-table-column label="排序" align="center" prop="sortOrder" />
<el-table-column label="是否启用" align="center" prop="isEnabled" />
<el-table-column label="备注" align="center" prop="remark" />
<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)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</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="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="form.categoryName" type="text" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="分类描述" prop="description">
<el-input v-model="form.description" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnabled">
<el-input v-model="form.isEnabled" placeholder="请输入是否启用" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addArticleCategory, delArticleCategory, getArticleCategory, listArticleCategory, updateArticleCategory } from "@/api/site/articleCategory";
import LanguageSelect from '@/components/LanguageSelect.vue';
export default {
name: "ArticleCategory",
components: {
LanguageSelect
},
data () {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 文章分类表格数据
articleCategoryList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
parentId: undefined,
langCode: undefined,
categoryName: undefined,
description: undefined,
sortOrder: undefined,
isEnabled: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created () {
this.getList();
},
methods: {
/** 查询文章分类列表 */
getList () {
this.loading = true;
listArticleCategory(this.queryParams).then(response => {
this.articleCategoryList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel () {
this.open = false;
this.reset();
},
// 表单重置
reset () {
this.form = {
categoryId: undefined,
parentId: undefined,
langCode: undefined,
categoryName: undefined,
description: undefined,
sortOrder: undefined,
isEnabled: undefined,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery () {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery () {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange (selection) {
this.ids = selection.map(item => item.categoryId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd () {
this.reset();
this.open = true;
this.title = "添加文章分类";
},
/** 修改按钮操作 */
handleUpdate (row) {
this.loading = true;
this.reset();
const categoryId = row.categoryId || this.ids
getArticleCategory(categoryId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改文章分类";
});
},
/** 提交按钮 */
submitForm () {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.categoryId != null) {
updateArticleCategory(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addArticleCategory(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete (row) {
const categoryIds = row.categoryId || this.ids;
this.$modal.confirm('是否确认删除文章分类编号为"' + categoryIds + '"的数据项?').then(() => {
this.loading = true;
return delArticleCategory(categoryIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport () {
this.download('export/articleCategory/export', {
...this.queryParams
}, `articleCategory_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -0,0 +1,356 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<LanguageSelect v-model="queryParams.langCode" placeholder="请选择语种" />
</el-form-item>
<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="caption">
<el-input
v-model="queryParams.caption"
placeholder="请输入轮播说明"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="图片链接" prop="imageUrl">
<el-input
v-model="queryParams.imageUrl"
placeholder="请输入图片链接"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="点击跳转 URL" prop="linkUrl">
<el-input
v-model="queryParams.linkUrl"
placeholder="请输入点击跳转 URL"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input
v-model="queryParams.sortOrder"
placeholder="请输入排序"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="是否启用" prop="isEnabled">
<el-input
v-model="queryParams.isEnabled"
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"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="carouselList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="轮播图主键" align="center" prop="carouselId" v-if="true"/> -->
<el-table-column label="语言编码" align="center" prop="langCode" />
<el-table-column label="轮播标题" align="center" prop="title" />
<el-table-column label="轮播说明" align="center" prop="caption" />
<el-table-column label="图片链接" align="center" prop="imageUrl">
<template slot-scope="scope">
<el-image
v-if="scope.row.imageUrl"
:src="scope.row.imageUrl"
:preview-src-list="[scope.row.imageUrl]"
style="max-width: 100px; max-height: 60px;"
fit="contain"
/>
</template>
</el-table-column>
<el-table-column label="点击跳转 URL" align="center" prop="linkUrl" />
<el-table-column label="排序" align="center" prop="sortOrder" />
<el-table-column label="是否启用" align="center" prop="isEnabled" />
<el-table-column label="备注" align="center" prop="remark" />
<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)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</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="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<LanguageSelect v-model="form.langCode" placeholder="请选择语种" />
</el-form-item>
<el-form-item label="轮播标题" prop="title">
<el-input v-model="form.title" placeholder="请输入轮播标题" />
</el-form-item>
<el-form-item label="轮播说明" prop="caption">
<el-input v-model="form.caption" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="图片链接" prop="imageUrl">
<el-input v-model="form.imageUrl" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="点击跳转 URL" prop="linkUrl">
<el-input v-model="form.linkUrl" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnabled">
<el-input v-model="form.isEnabled" placeholder="请输入是否启用" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addCarousel, delCarousel, getCarousel, listCarousel, updateCarousel } from "@/api/site/carousel";
import LanguageSelect from '@/components/LanguageSelect.vue';
export default {
name: "Carousel",
components: {
LanguageSelect
},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 轮播图表格数据
carouselList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
langCode: undefined,
title: undefined,
caption: undefined,
imageUrl: undefined,
linkUrl: undefined,
sortOrder: undefined,
isEnabled: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created() {
this.getList();
},
methods: {
/** 查询轮播图列表 */
getList() {
this.loading = true;
listCarousel(this.queryParams).then(response => {
this.carouselList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
carouselId: undefined,
langCode: undefined,
title: undefined,
caption: undefined,
imageUrl: undefined,
linkUrl: undefined,
sortOrder: undefined,
isEnabled: undefined,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.carouselId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加轮播图";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const carouselId = row.carouselId || this.ids
getCarousel(carouselId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改轮播图";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.carouselId != null) {
updateCarousel(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addCarousel(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const carouselIds = row.carouselId || this.ids;
this.$modal.confirm('是否确认删除轮播图编号为"' + carouselIds + '"的数据项?').then(() => {
this.loading = true;
return delCarousel(carouselIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('export/carousel/export', {
...this.queryParams
}, `carousel_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -0,0 +1,281 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<LanguageSelect v-model="queryParams.langCode" placeholder="请选择语种" />
</el-form-item>
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="分类描述" prop="description">
<el-input v-model="queryParams.description" placeholder="请输入分类描述" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="queryParams.sortOrder" placeholder="请输入排序" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnabled">
<el-input v-model="queryParams.isEnabled" 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="['export:category:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-if="refreshTable" v-loading="loading" :data="categoryList" row-key="categoryId"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
<el-table-column label="id" prop="categoryId" />
<!-- <el-table-column label="分类类型0=模块分类1=展示品分类" align="center" prop="type" /> -->
<!-- <el-table-column label="语言编码" align="center" prop="langCode" /> -->
<el-table-column label="分类名称" align="center" prop="categoryName" />
<el-table-column label="分类描述" align="center" prop="description" />
<el-table-column label="排序" align="center" prop="sortOrder" />
<el-table-column label="是否启用" align="center" prop="isEnabled" />
<el-table-column label="备注" align="center" prop="remark" />
<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="['export:category:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-plus" @click="handleAdd(scope.row)"
v-hasPermi="['export:category:add']">新增</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['export:category:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改分类对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="父分类ID" prop="parentId">
<treeselect v-model="form.parentId" :options="categoryOptions" :normalizer="normalizer"
placeholder="请选择父分类ID" />
</el-form-item>
<el-form-item label="分类名称" prop="categoryName">
<el-input v-model="form.categoryName" placeholder="请输入分类名称" />
</el-form-item>
<el-form-item label="分类描述" prop="description">
<el-input v-model="form.description" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnabled">
<el-input v-model="form.isEnabled" placeholder="请输入是否启用" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addCategory, delCategory, getCategory, listCategory, updateCategory } from "@/api/site/category";
import LanguageSelect from '@/components/LanguageSelect.vue';
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
name: "Category",
components: {
Treeselect,
LanguageSelect
},
data () {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 分类表格数据
categoryList: [],
// 分类树选项
categoryOptions: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
// 查询参数
queryParams: {
parentId: undefined,
type: undefined,
langCode: undefined,
categoryName: undefined,
description: undefined,
sortOrder: undefined,
isEnabled: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created () {
this.getList();
},
methods: {
/** 查询分类列表 */
getList () {
this.loading = true;
listCategory(this.queryParams).then(response => {
this.categoryList = this.handleTree(response.data, "categoryId", "parentId");
this.loading = false;
});
},
/** 转换分类数据结构 */
normalizer (node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.categoryId,
label: node.description,
children: node.children
};
},
/** 查询分类下拉树结构 */
getTreeselect () {
listCategory().then(response => {
this.categoryOptions = [];
const data = { categoryId: 0, categoryName: '顶级节点', description: '顶级节点', children: [] };
data.children = this.handleTree(response.data, "categoryId", "parentId");
this.categoryOptions.push(data);
});
},
// 取消按钮
cancel () {
this.open = false;
this.reset();
},
// 表单重置
reset () {
this.form = {
categoryId: null,
parentId: null,
type: null,
langCode: null,
categoryName: null,
description: null,
sortOrder: null,
isEnabled: null,
delFlag: null,
remark: null,
createTime: null,
createBy: null,
updateTime: null,
updateBy: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery () {
this.getList();
},
/** 重置按钮操作 */
resetQuery () {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd (row) {
this.reset();
this.getTreeselect();
if (row != null && row.categoryId) {
this.form.parentId = row.categoryId;
} else {
this.form.parentId = 0;
}
this.open = true;
this.title = "添加分类";
},
/** 展开/折叠操作 */
toggleExpandAll () {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 修改按钮操作 */
handleUpdate (row) {
this.loading = true;
this.reset();
this.getTreeselect();
if (row != null) {
this.form.parentId = row.categoryId;
}
getCategory(row.categoryId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改分类";
});
},
/** 提交按钮 */
submitForm () {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.categoryId != null) {
updateCategory(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addCategory(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete (row) {
this.$modal.confirm('是否确认删除分类编号为"' + row.categoryId + '"的数据项?').then(() => {
this.loading = true;
return delCategory(row.categoryId);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
}
}
};
</script>

View File

@@ -0,0 +1,360 @@
<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="langCode">
<LanguageSelect v-model="queryParams.langCode" placeholder="请选择语种" />
</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 label="联系邮箱" prop="email">
<el-input
v-model="queryParams.email"
placeholder="请输入联系邮箱"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="传真" prop="fax">
<el-input
v-model="queryParams.fax"
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="qrCode">
<el-input
v-model="queryParams.qrCode"
placeholder="请输入二维码链接"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="额外说明" prop="description">
<el-input
v-model="queryParams.description"
placeholder="请输入额外说明"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input
v-model="queryParams.sortOrder"
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"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="contactList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="联系方式主键" align="center" prop="contactId" v-if="true"/> -->
<el-table-column label="语言编码" align="center" prop="langCode" />
<el-table-column label="联系电话" align="center" prop="phone" />
<el-table-column label="联系邮箱" align="center" prop="email" />
<el-table-column label="传真" align="center" prop="fax" />
<el-table-column label="联系地址" align="center" prop="address" />
<el-table-column label="二维码链接" align="center" prop="qrCode" />
<el-table-column label="额外说明" align="center" prop="description" />
<el-table-column label="排序" align="center" prop="sortOrder" />
<el-table-column label="备注" align="center" prop="remark" />
<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)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</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="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<LanguageSelect v-model="form.langCode" 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="email">
<el-input v-model="form.email" placeholder="请输入联系邮箱" />
</el-form-item>
<el-form-item label="传真" prop="fax">
<el-input v-model="form.fax" placeholder="请输入传真" />
</el-form-item>
<el-form-item label="联系地址" prop="address">
<el-input v-model="form.address" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="二维码链接" prop="qrCode">
<el-input v-model="form.qrCode" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="额外说明" prop="description">
<el-input v-model="form.description" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addContact, delContact, getContact, listContact, updateContact } from "@/api/site/contact";
import LanguageSelect from '@/components/LanguageSelect.vue';
export default {
name: "Contact",
components: {
LanguageSelect
},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 联系方式表格数据
contactList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
langCode: undefined,
phone: undefined,
email: undefined,
fax: undefined,
address: undefined,
qrCode: undefined,
description: undefined,
sortOrder: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created() {
this.getList();
},
methods: {
/** 查询联系方式列表 */
getList() {
this.loading = true;
listContact(this.queryParams).then(response => {
this.contactList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
contactId: undefined,
langCode: undefined,
phone: undefined,
email: undefined,
fax: undefined,
address: undefined,
qrCode: undefined,
description: undefined,
sortOrder: undefined,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.contactId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加联系方式";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const contactId = row.contactId || this.ids
getContact(contactId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改联系方式";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.contactId != null) {
updateContact(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addContact(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const contactIds = row.contactId || this.ids;
this.$modal.confirm('是否确认删除联系方式编号为"' + contactIds + '"的数据项?').then(() => {
this.loading = true;
return delContact(contactIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('export/contact/export', {
...this.queryParams
}, `contact_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -0,0 +1,724 @@
<template>
<div class="app-container" style="display: flex;">
<!-- 左侧分类树 -->
<div style="width: 260px; margin-right: 20px;">
<el-tree :data="categoryOptions" node-key="categoryId" :props="treeProps" @node-click="handleCategoryClick"
default-expand-all highlight-current />
</div>
<!-- 右侧内容 -->
<div style="flex: 1;">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<LanguageSelect v-model="queryParams.langCode" placeholder="请选择语种" />
</el-form-item>
<el-form-item label="多语言键" prop="itemName">
<el-input v-model="queryParams.itemName" 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">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
@click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<ItemGroupTable v-loading="loading" :itemList="itemList" @update="handleUpdate" @delete="handleDelete" />
<!-- 新增展示品对话框独立 -->
<el-dialog title="添加展示品" :visible.sync="addOpen" width="800px" append-to-body>
<el-form ref="addFormRef" :model="addForm" :rules="addRules" label-width="100px">
<!-- 新增公共字段 -->
<el-row>
<el-col :span="8">
<el-form-item label="分类" prop="categoryId">
<treeselect v-model="addForm.categoryId" :options="categoryOptions" :normalizer="normalizer"
placeholder="请选择分类" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="多语言键" prop="itemName">
<el-input v-model="addForm.itemName" placeholder="请输入多语言键" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="简述" prop="description">
<el-input v-model="addForm.description" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-row>
<!-- 新增语言多选 + 动态正文 -->
<el-form-item label="选择语言" prop="selectedLangs">
<el-select v-model="addForm.selectedLangs" multiple placeholder="请选择需要添加的语言" style="width: 100%;"
@change="handleAddLangChange" :loading="langLoading">
<el-option v-for="lang in languageList" :key="lang.langCode"
:label="`${lang.languageName} (${lang.langCode})`" :value="lang.langCode"></el-option>
</el-select>
</el-form-item>
<!-- 动态正文输入框修复 prop 路径 -->
<div v-if="addForm.selectedLangs && addForm.selectedLangs.length > 0" class="lang-content-group">
<el-form-item v-for="(langCode, index) in addForm.selectedLangs" :key="langCode"
:label="`${getLangName(langCode)}正文`" :prop="`addLangContents.${index}.content`" :rules="[
{ required: true, message: `请输入${getLangName(langCode)}正文`, trigger: 'blur' }
]">
<el-input type="textarea" v-model="addForm.addLangContents[index].content"
:placeholder="`请输入${getLangName(langCode)}正文内容`" :min-height="120" />
</el-form-item>
</div>
<el-form-item label="备注" prop="remark">
<el-input v-model="addForm.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="addLoading" type="primary" @click="submitAdd"> </el-button>
<el-button @click="cancelAdd"> </el-button>
</div>
</el-dialog>
<!-- 修改展示品对话框独立 -->
<el-dialog title="修改展示品" :visible.sync="editOpen" width="800px" append-to-body>
<el-form ref="editFormRef" :model="editForm" :rules="editRules" label-width="100px">
<!-- 修改公共字段 -->
<el-row>
<el-col :span="8">
<el-form-item label="分类" prop="categoryId">
<treeselect v-model="editForm.categoryId" :options="categoryOptions" :normalizer="normalizer"
placeholder="请选择分类" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="多语言键" prop="itemName">
<el-input v-model="editForm.itemName" placeholder="请输入多语言键" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="语言编码" prop="langCode">
<el-select v-model="editForm.langCode" placeholder="请选择语言">
<el-option v-for="lang in languageList" :key="lang.langCode"
:label="`${lang.languageName} (${lang.langCode})`" :value="lang.langCode"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="简述" prop="description">
<el-input v-model="editForm.description" type="textarea" placeholder="请输入内容" />
</el-form-item>
<!-- 修改正文编辑区域增加普通文本/JSON切换 -->
<el-form-item label="正文" prop="content">
<!-- 切换按钮 -->
<el-button type="text" :class="{ 'text-primary': !editForm.isJsonMode }" @click="toggleEditMode(false)">
<i class="el-icon-font" style="margin-right: 4px;"></i>普通文本
</el-button>
<el-button type="text" :class="{ 'text-primary': editForm.isJsonMode }" @click="toggleEditMode(true)">
<i class="el-icon-code" style="margin-right: 4px;"></i>JSON格式
</el-button>
<!-- JSON模式提示 -->
<el-tooltip v-if="editForm.isJsonMode" content="支持JSON格式化和语法校验" placement="right">
<i class="el-icon-info" style="color: #409EFF; margin-left: 8px; cursor: pointer;"></i>
</el-tooltip>
<!-- 根据模式显示不同编辑器 -->
<div v-if="editForm.isJsonMode">
<json-editor v-model="editForm.jsonContent" :height="200"
:editor-options="{ mode: 'code', indentation: 2 }" @error="handleJsonError" />
</div>
<div v-else>
<el-input type="textarea" v-model="editForm.textContent" placeholder="请输入正文内容" :min-height="200"
resize="vertical" />
</div>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="editForm.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="editLoading" type="primary" @click="submitEdit"> </el-button>
<el-button @click="cancelEdit"> </el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import { listCategory } from "@/api/site/category";
import { addItem, delItem, getItem, listItem, updateItem } from "@/api/site/item";
import { listLanguage } from '@/api/site/language';
import JsonEditor from '@/components/JSONEditor/index.vue';
import LanguageSelect from '@/components/LanguageSelect.vue';
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import ItemGroupTable from "../panels/ItemGroupTable/index.vue";
import ItemTable from "../panels/ItemTable/index.vue";
export default {
name: "Item",
components: {
Treeselect,
LanguageSelect,
ItemGroupTable,
ItemTable,
JsonEditor,
},
data () {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 分类树选项
categoryOptions: [],
// 分类ID到描述的映射
categoryMap: {},
// 非单个禁用(修改按钮)
single: true,
// 非多个禁用(删除按钮)
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 展示品表格数据
itemList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 999,
categoryId: undefined,
langCode: undefined,
itemName: undefined,
description: undefined,
content: undefined,
accessory: undefined,
linkUrl: undefined,
itemType: undefined,
sortOrder: undefined,
isEnabled: undefined,
},
// 当前选中的分类ID
currentCategoryId: null,
// el-tree 配置
treeProps: {
label: 'description',
children: 'children'
},
// 语言列表从API获取
languageList: [],
// 语言加载状态
langLoading: false,
// ---------------------- 新增表单相关(独立)----------------------
addOpen: false, // 新增弹窗显示状态
addLoading: false, // 新增按钮loading
// 新增表单数据关键修改addLangContents 移到 addForm 内部)
addForm: {
categoryId: undefined,
selectedLangs: [], // 新增:多选语言编码
addLangContents: [], // 动态正文内容(移到 form 内部)
itemName: undefined,
description: undefined,
linkUrl: undefined,
sortOrder: undefined,
remark: undefined,
isEnabled: 1, // 默认启用
},
// 新增:附件输入框内容(多行字符串)
addAccessoryInput: '',
// 新增表单校验规则prop 路径对应 addForm.addLangContents
addRules: {
categoryId: [{ required: true, message: '请选择分类', trigger: 'change' }],
itemName: [{ required: true, message: '请输入多语言键', trigger: 'blur' }],
selectedLangs: [{ required: true, message: '请至少选择一种语言', trigger: 'change' }],
sortOrder: [{ required: true, message: '请输入排序', trigger: 'blur', type: 'number' }],
// 动态正文的校验规则已在 el-form-item 上内联定义(因为是动态的)
},
// ---------------------- 修改表单相关(独立)----------------------
editOpen: false, // 修改弹窗显示状态
editLoading: false, // 修改按钮loading
// 修改表单数据(新增编辑模式相关字段)
editForm: {
itemId: undefined,
categoryId: undefined,
langCode: undefined,
itemName: undefined,
description: undefined,
content: undefined, // 最终提交的正文内容(字符串)
textContent: '', // 普通文本模式的内容
jsonContent: {}, // JSON模式的内容对象
isJsonMode: false, // 编辑模式false=普通文本true=JSON
accessory: undefined,
linkUrl: undefined,
sortOrder: undefined,
remark: undefined,
isEnabled: 1,
},
// 修改:附件输入框内容(多行字符串)
editAccessoryInput: '',
// 修改表单校验规则调整content的校验逻辑
editRules: {
description: [{ required: true, message: '请输入简述', trigger: 'blur' }],
content: [
{ required: true, message: '请输入正文', trigger: 'blur' },
// JSON模式时额外校验格式
{
validator: (rule, value, callback) => {
if (this.editForm.isJsonMode && value) {
try {
JSON.parse(value);
callback();
} catch (e) {
callback(new Error('JSON格式错误请检查语法'));
}
} else {
callback();
}
},
trigger: 'blur'
}
],
sortOrder: [{ required: true, message: '请输入排序', trigger: 'blur', type: 'number' }],
}
};
},
created () {
this.getList();
this.getTreeselect();
this.fetchLanguageList(); // 初始化获取语言列表
// 监听编辑模式变化同步content值
this.$watch(
() => this.editForm.isJsonMode,
(newVal, oldVal) => {
if (newVal !== oldVal) {
this.syncEditContent();
}
}
);
// 监听textContent变化同步到content普通文本模式
this.$watch(
() => this.editForm.textContent,
(val) => {
if (!this.editForm.isJsonMode) {
this.editForm.content = val;
}
}
);
// 监听jsonContent变化同步到contentJSON模式
this.$watch(
() => this.editForm.jsonContent,
(val) => {
if (this.editForm.isJsonMode && val) {
try {
this.editForm.content = JSON.stringify(val, null, 2);
} catch (e) {
this.editForm.content = '';
}
}
},
{ deep: true }
);
},
methods: {
/** 查询展示品列表 */
getList () {
this.loading = true;
listItem(this.queryParams).then(response => {
this.itemList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 判断是否为JSON字符串 */
isJson (str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
},
/** 查询分类下拉树结构 */
getTreeselect () {
listCategory().then(response => {
this.categoryOptions = [];
const data = { categoryId: 0, categoryName: '顶级节点', description: '顶级节点', children: [] };
data.children = this.handleTree(response.data, "categoryId", "parentId");
this.categoryOptions.push(data);
// 构建categoryMap
this.categoryMap = {};
function buildMap (list) {
list.forEach(item => {
if (item.categoryId !== undefined) {
let desc = item.description || item.categoryName || String(item.categoryId);
if (item.categoryId !== 0) {
this.categoryMap[item.categoryId] = desc;
}
}
if (item.children && item.children.length) buildMap.call(this, item.children);
});
}
buildMap.call(this, this.categoryOptions);
});
},
/** 从API获取语言列表 */
fetchLanguageList () {
this.langLoading = true;
listLanguage({ pageSize: 1000 }).then(res => {
this.languageList = res.rows || [];
this.langLoading = false;
}).catch(() => {
this.langLoading = false;
this.$modal.msgError('获取语言列表失败');
});
},
/** 转换分类数据结构 */
normalizer (node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.categoryId,
label: node.description,
children: node.children
};
},
// 分类树点击事件
handleCategoryClick (node) {
this.currentCategoryId = node.categoryId;
this.queryParams.categoryId = node.categoryId;
this.queryParams.pageNum = 1;
this.getList();
},
/** 搜索按钮操作 */
handleQuery () {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery () {
this.$refs.queryForm.resetFields();
if (this.currentCategoryId) {
this.queryParams.categoryId = this.currentCategoryId;
} else {
this.queryParams.categoryId = undefined;
}
this.handleQuery();
},
// 表格多选框选中事件
handleSelectionChange (selection) {
this.ids = selection.map(item => item.itemId);
this.single = selection.length !== 1; // 选中1条时启用修改按钮
this.multiple = !selection.length; // 至少选中1条时启用删除按钮
},
// ---------------------- 新增表单操作(独立)----------------------
/** 新增按钮操作 */
handleAdd () {
this.resetAddForm(); // 重置新增表单
// 自动带入当前选中的分类
if (this.currentCategoryId) {
this.addForm.categoryId = this.currentCategoryId;
}
this.addOpen = true;
},
/** 重置新增表单 */
resetAddForm () {
this.addForm = {
categoryId: this.currentCategoryId || undefined,
selectedLangs: [],
addLangContents: [], // 重置动态正文数组
itemName: undefined,
description: undefined,
linkUrl: undefined,
sortOrder: undefined,
remark: undefined,
isEnabled: 1,
};
this.addAccessoryInput = '';
if (this.$refs.addFormRef) {
this.$refs.addFormRef.resetFields();
}
},
/** 取消新增 */
cancelAdd () {
this.addOpen = false;
this.resetAddForm();
},
/** 新增:语言选择变化时,同步动态正文数组(修改为操作 addForm.addLangContents */
handleAddLangChange (selectedLangs) {
this.addForm.addLangContents = selectedLangs.map(langCode => {
// 保留已输入的正文内容
const existing = this.addForm.addLangContents.find(item => item.langCode === langCode);
return existing || { langCode, content: '' };
});
},
/** 提交新增表单(批量新增多语言) */
submitAdd () {
// 处理附件:多行转逗号分隔
const accessory = this.addAccessoryInput
.split('\n')
.map(s => s.trim())
.filter(s => s)
.join(',');
this.$refs.addFormRef.validate(valid => {
if (valid) {
this.addLoading = true;
// 构建每个语言的新增请求参数(从 addForm.addLangContents 取值)
const requestList = this.addForm.selectedLangs.map((langCode, index) => ({
categoryId: this.addForm.categoryId,
langCode,
itemName: this.addForm.itemName,
description: this.addForm.description,
content: this.addForm.addLangContents[index].content, // 修复取值路径
accessory,
linkUrl: this.addForm.linkUrl,
sortOrder: this.addForm.sortOrder,
isEnabled: this.addForm.isEnabled,
remark: this.addForm.remark,
}));
// 并发提交所有语言的新增请求
Promise.all(requestList.map(params => addItem(params)))
.then(() => {
this.$modal.msgSuccess("新增成功");
this.addOpen = false;
this.getList();
})
.catch(error => {
this.$modal.msgError(error.message || "新增失败");
})
.finally(() => {
this.addLoading = false;
});
}
});
},
// ---------------------- 修改表单操作(独立)----------------------
/** 修改按钮操作 */
handleUpdate (row) {
const itemId = row && row.itemId ? row.itemId : this.ids[0]; // 优先取行数据,其次取选中的第一条
this.loading = true;
getItem(itemId).then(response => {
this.loading = false;
const data = { ...response.data };
// 初始化编辑模式和内容
const isJson = this.isJson(data.content || '');
this.editForm = {
...data,
isJsonMode: isJson,
textContent: isJson ? JSON.stringify(data.content, null, 2) : data.content || '',
jsonContent: isJson ? JSON.parse(data.content) : {},
};
// 附件回显:逗号分隔转多行
this.editAccessoryInput = this.editForm.accessory
? this.editForm.accessory.split(',').join('\n')
: '';
this.editOpen = true;
});
},
/** 切换编辑模式(普通文本/JSON */
toggleEditMode (isJsonMode) {
this.editForm.isJsonMode = isJsonMode;
},
/** 同步编辑内容(模式切换时调用) */
syncEditContent () {
if (this.editForm.isJsonMode) {
// 普通文本 → JSON尝试解析为JSON对象
try {
this.editForm.jsonContent = this.editForm.content
? JSON.parse(this.editForm.content)
: {};
} catch (e) {
// this.editForm.jsonContent = {};
this.$modal.msgWarning('当前文本无法解析为JSON');
}
} else {
// JSON → 普通文本转为格式化的JSON字符串
this.editForm.textContent = this.editForm.jsonContent
? JSON.stringify(this.editForm.jsonContent, null, 2)
: '';
}
},
/** JSON编辑错误处理 */
handleJsonError (error) {
this.$modal.msgError(`JSON编辑错误${error.message}`);
},
/** 重置修改表单 */
resetEditForm () {
this.editForm = {
itemId: undefined,
categoryId: undefined,
langCode: undefined,
itemName: undefined,
description: undefined,
content: undefined,
textContent: '',
jsonContent: {},
isJsonMode: false,
accessory: undefined,
linkUrl: undefined,
sortOrder: undefined,
remark: undefined,
isEnabled: 1,
};
this.editAccessoryInput = '';
if (this.$refs.editFormRef) {
this.$refs.editFormRef.resetFields();
}
},
/** 取消修改 */
cancelEdit () {
this.editOpen = false;
this.resetEditForm();
},
/** 提交修改表单(单语言修改) */
submitEdit () {
// 处理附件:多行转逗号分隔
const accessory = this.editAccessoryInput
.split('\n')
.map(s => s.trim())
.filter(s => s)
.join(',');
this.$refs.editFormRef.validate(valid => {
if (valid) {
this.editLoading = true;
// 构建修改请求参数确保content是字符串格式
const editParams = {
...this.editForm,
accessory, // 更新处理后的附件
content: this.editForm.content || '', // 确保提交字符串
};
updateItem(editParams)
.then(() => {
this.$modal.msgSuccess("修改成功");
this.editOpen = false;
this.getList();
})
.catch(error => {
this.$modal.msgError(error.message || "修改失败");
})
.finally(() => {
this.editLoading = false;
});
}
});
},
// ---------------------- 公共操作 ----------------------
/** 删除按钮操作 */
handleDelete (row) {
const itemIds = row && row.itemId ? row.itemId : this.ids;
this.$modal.confirm(`是否确认删除展示品编号为"${itemIds}"的数据项?`).then(() => {
this.loading = true;
return delItem(itemIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport () {
this.download('export/item/export', {
...this.queryParams
}, `item_${new Date().getTime()}.xlsx`);
},
/** 根据语言编码获取语言名称 */
getLangName (langCode) {
const lang = this.languageList.find(item => item.langCode === langCode);
return lang ? lang.languageName : langCode;
},
/** 树形数据处理 */
handleTree (data, id, parentId) {
const result = [];
const map = {};
data.forEach(item => {
map[item[id]] = item;
});
data.forEach(item => {
const parent = map[item[parentId]];
if (parent) {
(parent.children || (parent.children = [])).push(item);
} else {
result.push(item);
}
});
return result;
}
}
};
</script>
<style scoped>
.lang-content-group {
margin-top: 10px;
}
.lang-content-group .el-form-item {
margin-bottom: 20px;
}
/* 切换按钮样式优化 */
.mb4 {
margin-bottom: 4px !important;
}
.text-primary {
color: #409eff !important;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,305 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<el-input
v-model="queryParams.langCode"
placeholder="请输入语言编码"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="语言名称" prop="languageName">
<el-input
v-model="queryParams.languageName"
placeholder="请输入语言名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="是否默认语言" prop="isDefault">
<el-input
v-model="queryParams.isDefault"
placeholder="请输入是否默认语言"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> -->
<el-form-item label="排序" prop="sortOrder">
<el-input
v-model="queryParams.sortOrder"
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"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="languageList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="语言主键" align="center" prop="languageId" v-if="true"/> -->
<el-table-column label="语言编码" align="center" prop="langCode" />
<el-table-column label="语言名称" align="center" prop="languageName" />
<!-- <el-table-column label="是否默认语言" align="center" prop="isDefault" /> -->
<el-table-column label="排序" align="center" prop="sortOrder" />
<el-table-column label="备注" align="center" prop="remark" />
<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)"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</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="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="语言编码" prop="langCode">
<el-input v-model="form.langCode" placeholder="请输入语言编码" />
</el-form-item>
<el-form-item label="语言名称" prop="languageName">
<el-input v-model="form.languageName" placeholder="请输入语言名称" />
</el-form-item>
<!-- <el-form-item label="是否默认语言" prop="isDefault">
<el-input v-model="form.isDefault" placeholder="请输入是否默认语言" />
</el-form-item> -->
<el-form-item label="排序" prop="sortOrder">
<el-input v-model="form.sortOrder" placeholder="请输入排序" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addLanguage, delLanguage, getLanguage, listLanguage, updateLanguage } from "@/api/site/language";
export default {
name: "Language",
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 语言管理表格数据
languageList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
langCode: undefined,
languageName: undefined,
isDefault: undefined,
sortOrder: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
}
};
},
created() {
this.getList();
},
methods: {
/** 查询语言管理列表 */
getList() {
this.loading = true;
listLanguage(this.queryParams).then(response => {
this.languageList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
languageId: undefined,
langCode: undefined,
languageName: undefined,
isDefault: undefined,
sortOrder: undefined,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.languageId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加语言管理";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const languageId = row.languageId || this.ids
getLanguage(languageId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改语言管理";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.languageId != null) {
updateLanguage(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addLanguage(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const languageIds = row.languageId || this.ids;
this.$modal.confirm('是否确认删除语言管理编号为"' + languageIds + '"的数据项?').then(() => {
this.loading = true;
return delLanguage(languageIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('export/language/export', {
...this.queryParams
}, `language_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -0,0 +1,94 @@
<template>
<el-table :data="groupedItems" height="500px" row-key="itemName" :expand-row-keys="defaultExpandedRows">
<!-- 展开行内容 -->
<el-table-column type="expand">
<template slot-scope="scope">
<el-table :data="scope.row.languages" border size="mini" style="width: 100%; margin-top: 10px;">
<el-table-column label="语言编码" align="center" prop="langCode" width="120" />
<el-table-column label="正文" align="center" prop="content" show-overflow-tooltip />
<el-table-column label="是否启用" align="center" prop="isEnabled" width="100" />
<el-table-column label="操作" align="center" width="140">
<template slot-scope="langScope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(langScope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete"
@click="handleDelete(langScope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<el-table-column label="多语言键" align="center" prop="itemName" />
<el-table-column label="描述" align="center" prop="description" />
<el-table-column label="排序" align="center" prop="sortOrder" width="80" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="语言数量" align="center" width="100">
<template slot-scope="scope">{{ scope.row.languages.length }}</template>
</el-table-column>
<!-- <el-table-column label="操作" align="center" width="160">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-plus" @click="handleAddLanguage(scope.row)">添加语言</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEditMain(scope.row)">编辑主信息</el-button>
</template>
</el-table-column> -->
</el-table>
</template>
<script>
export default {
name: "GroupedItemTable",
props: {
itemList: {
type: Array,
default: () => [],
},
// 可设置默认展开的行
defaultExpanded: {
type: Array,
default: () => [],
},
},
computed: {
// 按多语言键分组数据
groupedItems () {
const groups = {};
// 遍历原始数据进行分组
this.itemList.forEach(item => {
if (!groups[item.itemName]) {
// 初始化分组,提取共同属性
groups[item.itemName] = {
itemName: item.itemName,
description: item.description,
sortOrder: item.sortOrder,
remark: item.remark,
languages: []
};
}
// 将当前语言项添加到对应分组
groups[item.itemName].languages.push({
...item
});
});
return Object.values(groups);
},
// 默认展开的行
defaultExpandedRows () {
return this.defaultExpanded;
}
},
methods: {
// 修改语言项
handleUpdate (row) {
this.$emit("update", row);
},
// 删除语言项
handleDelete (row) {
this.$emit("delete", row);
},
}
}
</script>

View File

@@ -0,0 +1,60 @@
<template>
<el-table :data="itemList" height="500px">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<!-- <el-table-column label="所属分类" align="center" prop="categoryId" :formatter="categoryDescFormatter" /> -->
<el-table-column label="语言编码" align="center" prop="langCode" />
<el-table-column label="多语言键" align="center" prop="itemName" />
<el-table-column label="描述" align="center" prop="description" />
<el-table-column label="正文" align="center" prop="content" show-overflow-tooltip />
<!-- <el-table-column label="外链 URL" align="center" prop="linkUrl" /> -->
<!-- <el-table-column label="附件" align="center" prop="accessory"> -->
<!-- <template slot-scope="scope">
<div v-if="scope.row.accessory">
<div v-for="(url, idx) in $options.methods.parseAccessory(scope.row.accessory)" :key="idx"
style="display:inline-block;margin-right:12px;vertical-align:middle;">
<template v-if="$options.methods.isImage(url)">
<i class="el-icon-picture-outline" style="color:#409EFF;margin-right:4px;vertical-align:middle;"></i>
<el-image :src="url" :preview-src-list="[url]"
style="width:40px;height:40px;object-fit:cover;vertical-align:middle;border-radius:4px;border:1px solid #eee;"
fit="cover" />
</template>
<template v-else>
<i class="el-icon-link" style="color:#409EFF;margin-right:4px;vertical-align:middle;"></i>
<a :href="url" target="_blank"
style="color:#409EFF;text-decoration:underline;vertical-align:middle;">附件{{ idx + 1 }}</a>
</template>
</div>
</div>
</template>
</el-table-column> -->
<el-table-column label="排序" align="center" prop="sortOrder" />
<el-table-column label="是否启用" align="center" prop="isEnabled" />
<el-table-column label="备注" align="center" prop="remark" />
<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)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
name: "ItemTable",
props: {
itemList: {
type: Array,
default: () => [],
},
},
methods: {
handleUpdate (row) {
this.$emit("update", row);
},
handleDelete (row) {
this.$emit("delete", row);
},
}
}
</script>