Commit 225e0249 authored by shangtx's avatar shangtx

feat: 服务详情

parent de622e79
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
"vue": "2.6.11", "vue": "2.6.11",
"vue-ls": "3.2.0", "vue-ls": "3.2.0",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vuex": "3.0.1" "vuex": "3.0.1",
"wangeditor": "^4.7.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-transform-runtime": "7.2.0", "@babel/plugin-transform-runtime": "7.2.0",
...@@ -1537,6 +1538,23 @@ ...@@ -1537,6 +1538,23 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@babel/runtime-corejs3": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz",
"integrity": "sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==",
"dependencies": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"node_modules/@babel/runtime/node_modules/regenerator-runtime": { "node_modules/@babel/runtime/node_modules/regenerator-runtime": {
"version": "0.12.1", "version": "0.12.1",
"license": "MIT" "license": "MIT"
...@@ -4600,6 +4618,16 @@ ...@@ -4600,6 +4618,16 @@
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
}, },
"node_modules/core-js-pure": {
"version": "3.23.5",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.5.tgz",
"integrity": "sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/core-util-is": { "node_modules/core-util-is": {
"version": "1.0.3", "version": "1.0.3",
"dev": true, "dev": true,
...@@ -13484,6 +13512,32 @@ ...@@ -13484,6 +13512,32 @@
"version": "3.0.1", "version": "3.0.1",
"license": "MIT" "license": "MIT"
}, },
"node_modules/wangeditor": {
"version": "4.7.15",
"resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-4.7.15.tgz",
"integrity": "sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==",
"dependencies": {
"@babel/runtime": "^7.11.2",
"@babel/runtime-corejs3": "^7.11.2",
"tslib": "^2.1.0"
}
},
"node_modules/wangeditor/node_modules/@babel/runtime": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
"dependencies": {
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/wangeditor/node_modules/regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"node_modules/warning": { "node_modules/warning": {
"version": "4.0.3", "version": "4.0.3",
"license": "MIT", "license": "MIT",
...@@ -15418,6 +15472,22 @@ ...@@ -15418,6 +15472,22 @@
} }
} }
}, },
"@babel/runtime-corejs3": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz",
"integrity": "sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==",
"requires": {
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
}
}
},
"@babel/template": { "@babel/template": {
"version": "7.18.6", "version": "7.18.6",
"dev": true, "dev": true,
...@@ -17633,6 +17703,11 @@ ...@@ -17633,6 +17703,11 @@
} }
} }
}, },
"core-js-pure": {
"version": "3.23.5",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.5.tgz",
"integrity": "sha512-8t78LdpKSuCq4pJYCYk8hl7XEkAX+BP16yRIwL3AanTksxuEf7CM83vRyctmiEL8NDZ3jpUcv56fk9/zG3aIuw=="
},
"core-util-is": { "core-util-is": {
"version": "1.0.3", "version": "1.0.3",
"dev": true "dev": true
...@@ -23779,6 +23854,31 @@ ...@@ -23779,6 +23854,31 @@
"vuex": { "vuex": {
"version": "3.0.1" "version": "3.0.1"
}, },
"wangeditor": {
"version": "4.7.15",
"resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-4.7.15.tgz",
"integrity": "sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==",
"requires": {
"@babel/runtime": "^7.11.2",
"@babel/runtime-corejs3": "^7.11.2",
"tslib": "^2.1.0"
},
"dependencies": {
"@babel/runtime": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
}
}
},
"warning": { "warning": {
"version": "4.0.3", "version": "4.0.3",
"requires": { "requires": {
......
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
"vue": "2.6.11", "vue": "2.6.11",
"vue-ls": "3.2.0", "vue-ls": "3.2.0",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vuex": "3.0.1" "vuex": "3.0.1",
"wangeditor": "^4.7.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-transform-runtime": "7.2.0", "@babel/plugin-transform-runtime": "7.2.0",
......
<!--
基于wangEditor的vue的富文本编辑器,请通过组件的ref直接设置和获取富文本内容
由于wangEditor本身的特性(也许是bug),通过双向绑定和回调函数的方式直接修改外部的内容变量会引发末尾回车键失效的问题
文档地址 https://www.wangeditor.com/doc/
-->
<template>
<a-spin :spinning="loading">
<div class="wangeditor-atkj-wrapper" :id="id"></div>
</a-spin>
</template>
<script>
// 引入 wangEditor
import wangEditor from 'wangeditor'
export default {
name: 'RichTextEditor',
props: {
id: {
type: String,
default: () => 'wangeditor-atkj-wrapper-default-id'
},
height: {
type: Number,
default: () => 300
},
videoSizeLimit: {
type: Number,
default: () => 100
},
isSessionStorage: {
type: Boolean,
default: () => false
}
},
data() {
return {
editor: null,
loading: false
}
},
beforeDestroy() {
this.editor.destroy()
this.editor = null
},
mounted() {
if (this.editor != null) {
return
}
this.init()
},
activated() {
if (this.editor != null) {
return
}
this.init()
},
methods: {
// 设置内容
setContent(v) {
this.editor.txt.html(v)
},
// 获取内容
getContent() {
return this.editor.txt.html()
},
// 清空内容
clear() {
this.editor.txt.clear()
},
init() {
const _this = this
const editor = new wangEditor(`.wangeditor-atkj-wrapper#${this.id}`)
// 配置 onchange 回调函数,将数据同步到 vue 中
editor.config.showLinkImg = false //关闭网络路径图片方式
editor.config.uploadImgServer = `${process.env.VUE_APP_URL}upload?fileType=IMG`
editor.config.uploadFileName = 'files' // formdata中的name属性
var token = ''
if (this.isSessionStorage) {
token = sessionStorage.getItem('token')
} else {
token = localStorage.getItem('token')
}
editor.config.uploadImgHeaders = {
// todo 设置请求头
Authorization: token // 设置请求头
}
// 设置高度
editor.config.height = this.height
editor.config.uploadVideoServer = `${process.env.VUE_APP_URL}upload?fileType=VIDEO`
editor.config.uploadVideoName = 'files'
editor.config.uploadVideoHeaders = {
Authorization: localStorage.getItem('token') // 设置请求头
}
editor.config.uploadVideoMaxSize = 1024 * this.videoSizeLimit
editor.config.zIndex = 0
editor.config.uploadImgHooks = {
// 图片上传并返回结果,但图片插入错误时触发
fail: function (xhr, editor, result) {
console.error('richTextError', result)
},
// eslint-disable-next-line no-unused-vars
success: function (xhr, editor, result) {
// 图片上传并返回结果,图片插入成功之后触发
},
/**
* insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
* result 即服务端返回的接口
*/
customInsert: function (insertImgFn, result) {
insertImgFn(result.data.urls[0])
}
}
editor.config.uploadVideoHooks = {
// 视频上传并返回了结果,想要自己把视频插入到编辑器中
// 例如服务器端返回的不是 { errno: 0, data: { url : '.....'} } 这种格式,可使用 customInsert
customInsert: function (insertVideoFn, result) {
// result 即服务端返回的接口
// insertVideoFn 可把视频插入到编辑器,传入视频 src ,执行函数即可
if (result.code == 200) {
insertVideoFn(result.data.urls[0])
} else {
_this.$message.error('上传失败')
_this.loading = false
}
},
before() {
_this.loading = true
},
fail() {
_this.loading = false
},
// 上传视频出错,一般为 http 请求的错误
error() {
_this.loading = false
},
// 上传视频超时
timeout() {
_this.loading = false
}
}
// 自定义插入视频, 主要用来处理loading状态
editor.config.customInsertVideo = function (url) {
const videoElement = document.createElement('video')
videoElement.setAttribute('controls', 'controls')
videoElement.setAttribute('style', 'max-width:100%')
videoElement.setAttribute('src', url)
// 4、loadeddata:视频下载监听。当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时触发
// eslint-disable-next-line no-unused-vars
videoElement.addEventListener('loadeddata', function (e) {
_this.loading = false
})
/**
* 此处参考
* https://github.com/wangeditor-team/wangEditor/blob/master/src/editor/command.ts insertElem
*/
const range = editor.selection.getRange()
if (range == null) return
if (range.insertNode) {
range.insertNode(videoElement)
}
}
// 内容change
// eslint-disable-next-line no-unused-vars
editor.config.onchange = (_newHtml) => {}
// 创建编辑器
editor.create()
this.editor = editor
}
},
// beforeDestroy() {
// 调用销毁 API 对当前编辑器实例进行销毁
// }
}
</script>
<style lang="less">
.wangeditor-atkj-wrapper {
.home {
width: 1200px;
margin: auto;
position: relative;
}
.home .btn {
position: absolute;
right: 0;
top: 0;
padding: 5px 10px;
cursor: pointer;
}
.home h3 {
margin: 30px 0 15px;
}
.w-e-text-container {
border: 1px solid #c9d8db;
border-top: none;
z-index: 25;
}
.w-e-toolbar {
z-index: 28 !important;
}
}
</style>
<template>
<a-drawer :width="500" :visible="visible" title="服务类别" @close="close">
<a-form :form="form" layout="vertical">
<a-form-item label="名称">
<a-input v-decorator="['serviceName']" />
</a-form-item>
<a-form-item label="次级标题">
<a-input v-decorator="['description']" />
</a-form-item>
<a-form-item label="排序">
<a-input-number v-decorator="['sequence']" />
</a-form-item>
</a-form>
<div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
<a-button type="primary" @click="submit"> 保存 </a-button>
</div>
</a-drawer>
</template>
<script>
import { updateCategory, getDetails } from '@/api/serv'
export default {
name: 'CategoryEdit',
props: { success: Function },
data() {
return {
form: this.$form.createForm(this),
visible: false,
id: null,
categoryId: null,
categoryName: ''
}
},
methods: {
show(id) {
this.id = id
this.visible = true
if (id) {
getDetails(this.id).then(({ data }) => {
this.form.setFieldsValue(data)
})
}
},
close() {
this.id = null
this.form.resetFields()
this.visible = false
},
submit() {
this.form.validateFields((err, values) => {
if (err) {
return
}
const reqData = {
...values,
id: this.id
}
updateCategory(reqData).then(({ code }) => {
if (code == 200) {
this.$message.success('保存成功')
this.close()
this.success()
}
})
})
}
}
}
</script>
\ No newline at end of file
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<a-space> <a-space>
<template v-if="record.type == 1"> <template v-if="record.type == 1">
<a @click="add(record)">添加服务项</a> <a @click="add(record)">添加服务项</a>
<a @click="editCategory(record)">修改信息</a>
</template> </template>
<template v-if="record.type == 2"> <template v-if="record.type == 2">
<a @click="edit(record)">修改信息</a> <a @click="edit(record)">修改信息</a>
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
</template> </template>
<template #free> <template #free>
<SubClassEdit ref="SubClassEdit" :success="reset" /> <SubClassEdit ref="SubClassEdit" :success="reset" />
<CategoryEdit ref="CategoryEdit" :success="reset" />
</template> </template>
</table-template> </table-template>
</template> </template>
...@@ -29,6 +31,7 @@ ...@@ -29,6 +31,7 @@
import { TableTemplate, TableScript, SearchType } from '@/components/table' import { TableTemplate, TableScript, SearchType } from '@/components/table'
import { getCategoryList, saveOrUpdateSubClass } from '@/api/serv' import { getCategoryList, saveOrUpdateSubClass } from '@/api/serv'
import SubClassEdit from './SubClassEdit.vue' import SubClassEdit from './SubClassEdit.vue'
import CategoryEdit from './CategoryEdit.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
const columns = [ const columns = [
...@@ -61,7 +64,7 @@ const columns = [ ...@@ -61,7 +64,7 @@ const columns = [
export default { export default {
name: 'ServiceList', name: 'ServiceList',
mixins: [TableScript, {}], mixins: [TableScript, {}],
components: { TableTemplate, SubClassEdit }, components: { TableTemplate, SubClassEdit, CategoryEdit },
data() { data() {
return { return {
columns, columns,
...@@ -76,7 +79,6 @@ export default { ...@@ -76,7 +79,6 @@ export default {
methods: { methods: {
queryData: getCategoryList, queryData: getCategoryList,
loadSuccess() { loadSuccess() {
console.info('xxxxxxxxxssssssssssss')
this.expandedRowKeys = this.dataSource.map((d) => d.id + '') this.expandedRowKeys = this.dataSource.map((d) => d.id + '')
}, },
enableChange(record, index) { enableChange(record, index) {
...@@ -118,6 +120,9 @@ export default { ...@@ -118,6 +120,9 @@ export default {
categoryId: record.id, categoryId: record.id,
categoryName: record.serviceName categoryName: record.serviceName
}) })
},
editCategory(record) {
this.$refs.CategoryEdit.show(record.id)
} }
} }
} }
......
<template> <template>
<a-drawer <a-drawer
:width="500" :width="1000"
:visible="visible" :visible="visible"
:title="id ? '编辑服务项' : '新增服务项'" :title="id ? '编辑服务项' : '新增服务项'"
@close="close" @close="close"
> >
<a-form :form="form" layout="vertical"> <a-form :form="form" layout="vertical">
<a-form-item :label="`服务大类: ${categoryName}`"> </a-form-item> <a-row>
<a-form-item label="名称"> <a-form-item :label="`服务大类: ${categoryName}`"> </a-form-item>
<a-input v-decorator="['serviceName']" /> <a-col :span="11">
</a-form-item> <a-form-item label="名称">
<ImageUpload <a-input v-decorator="['serviceName']" />
label="图片" </a-form-item>
decoration="img" </a-col>
:formItemLayout="null" <a-col :span="11" :offset="1">
:required="true" <a-form-item label="次级标题">
ref="image" <a-input v-decorator="['description']" />
:form="form" </a-form-item>
/> </a-col>
<a-form-item label="排序"> <a-col :span="11">
<a-input-number v-decorator="['sequence']" /> <ImageUpload
</a-form-item> label="图片"
decoration="img"
:formItemLayout="null"
:required="true"
ref="image"
:form="form"
/>
</a-col>
<a-col :span="11" :offset="1">
<a-form-item label="排序">
<a-input-number v-decorator="['sequence']" />
</a-form-item>
</a-col>
<a-col :span="23">
<a-form-item label="服务详情">
<RichText ref="RichText" />
</a-form-item>
</a-col>
</a-row>
</a-form> </a-form>
<div class="drawer-form-bottom-toolbar"> <div class="drawer-form-bottom-toolbar">
<a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button> <a-button :style="{ marginRight: '8px' }" @click="close"> 取消 </a-button>
...@@ -31,10 +49,11 @@ ...@@ -31,10 +49,11 @@
<script> <script>
import ImageUpload from '@/components/image-upload/ImageUpload' import ImageUpload from '@/components/image-upload/ImageUpload'
import { saveOrUpdateSubClass, getSubDetails } from '@/api/serv' import { saveOrUpdateSubClass, getSubDetails } from '@/api/serv'
import RichText from '@/components/richtext/richtext-editor'
export default { export default {
name: 'SubClassEdit', name: 'SubClassEdit',
components: { ImageUpload }, components: { ImageUpload, RichText },
props: { success: Function }, props: { success: Function },
data() { data() {
return { return {
...@@ -55,6 +74,7 @@ export default { ...@@ -55,6 +74,7 @@ export default {
getSubDetails(this.id).then(({ data }) => { getSubDetails(this.id).then(({ data }) => {
this.form.setFieldsValue(data) this.form.setFieldsValue(data)
this.$refs.image.setValue([data.img]) this.$refs.image.setValue([data.img])
this.$refs.RichText.setContent(data.textDescription)
}) })
} }
}, },
...@@ -64,6 +84,7 @@ export default { ...@@ -64,6 +84,7 @@ export default {
this.categoryName = '' this.categoryName = ''
this.$refs.image.reset() this.$refs.image.reset()
this.form.resetFields() this.form.resetFields()
this.$refs.RichText.clear()
this.visible = false this.visible = false
}, },
submit() { submit() {
...@@ -75,7 +96,8 @@ export default { ...@@ -75,7 +96,8 @@ export default {
...values, ...values,
img: this.$refs.image.getValue()[0], img: this.$refs.image.getValue()[0],
id: this.id, id: this.id,
categoryId: this.categoryId categoryId: this.categoryId,
textDescription: this.$refs.RichText.getContent()
} }
saveOrUpdateSubClass(reqData).then(({ code }) => { saveOrUpdateSubClass(reqData).then(({ code }) => {
if (code == 200) { if (code == 200) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment