contentOperation.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <template>
  2. <div class="m-container">
  3. <h2>
  4. <el-page-header @back="onCancel"
  5. :content="(pageType == 'create' ? '添加' : '修改') + typeChange(type)"></el-page-header>
  6. </h2>
  7. <div class="m-core">
  8. <el-form :model="form"
  9. :rules="rules"
  10. ref="form"
  11. label-width="120px"
  12. style="width: 100%">
  13. <el-form-item label="标题"
  14. prop="title">
  15. <el-input v-model="form.title"></el-input>
  16. </el-form-item>
  17. <el-form-item label="排序值">
  18. <el-input v-model="form.order"></el-input>
  19. </el-form-item>
  20. <el-form-item label="链接地址"
  21. prop="linkUrl">
  22. <el-input v-model="form.linkUrl"></el-input>
  23. </el-form-item>
  24. <el-form-item label="封面图"
  25. prop="coverImage">
  26. <el-upload class="avatar-uploader"
  27. action="/api-web/uploadFile"
  28. :headers="headers"
  29. :show-file-list="false"
  30. :on-success="handleAvatarSuccess"
  31. :before-upload="beforeAvatarUpload">
  32. <img v-if="form.coverImage"
  33. :src="form.coverImage"
  34. class="avatar">
  35. <i v-else
  36. class="el-icon-plus avatar-uploader-icon"></i>
  37. </el-upload>
  38. <p class="imageSize"
  39. v-if="imageSize">上传图片尺寸为:{{ imageSize }}</p>
  40. </el-form-item>
  41. <el-form-item label="内容"
  42. prop="content">
  43. <!-- bidirectional data binding(双向数据绑定) -->
  44. <quill-editor v-model="form.content"
  45. ref="myQuillEditor"
  46. :options="editorOption"
  47. @change="onEditorChange($event)">
  48. </quill-editor>
  49. <el-upload class="ivu-upload"
  50. :show-upload-list="false"
  51. :headers="headers"
  52. :on-success="handleSuccess"
  53. :format="['jpg','jpeg','png','gif']"
  54. :max-size="2048"
  55. multiple
  56. action="/api-web/uploadFile">
  57. <Button icon="ios-cloud-upload-outline"></Button>
  58. </el-upload>
  59. </el-form-item>
  60. <el-form-item>
  61. <el-button @click="onSubmit('form')"
  62. type="primary">立即{{ pageType == "create" ? '创建' : '修改' }}</el-button>
  63. <el-button @click="onReSet('form')">重置</el-button>
  64. </el-form-item>
  65. </el-form>
  66. </div>
  67. </div>
  68. </template>
  69. <script>
  70. import { newsQueryId, newsAdd, newsUpdate } from '@/api/contentManager'
  71. import store from '@/store'
  72. import { getToken } from '@/utils/auth'
  73. import { vaildStudentUrl } from '@/utils/validate'
  74. // import E from 'wangeditor'
  75. // require styles
  76. import 'quill/dist/quill.core.css'
  77. import 'quill/dist/quill.snow.css'
  78. import 'quill/dist/quill.bubble.css'
  79. import { quillEditor } from 'vue-quill-editor'
  80. // 工具栏配置
  81. const toolbarOptions = [
  82. ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
  83. ["blockquote", "code-block"], // 引用 代码块
  84. [{ header: 1 }, { header: 2 }], // 1、2 级标题
  85. [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
  86. [{ script: "sub" }, { script: "super" }], // 上标/下标
  87. [{ indent: "-1" }, { indent: "+1" }], // 缩进
  88. // [{'direction': 'rtl'}], // 文本方向
  89. [{ size: ["small", false, "large", "huge"] }], // 字体大小
  90. [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  91. [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
  92. [{ font: [] }], // 字体种类
  93. [{ align: [] }], // 对齐方式
  94. ["clean"], // 清除文本格式
  95. ["link", "image", "video"] // 链接、图片、视频
  96. ];
  97. // 标题
  98. const titleConfig = {
  99. 'ql-bold': '加粗',
  100. 'ql-color': '颜色',
  101. 'ql-font': '字体',
  102. 'ql-code': '插入代码',
  103. 'ql-italic': '斜体',
  104. 'ql-link': '添加链接',
  105. 'ql-background': '背景颜色',
  106. 'ql-size': '字体大小',
  107. 'ql-strike': '删除线',
  108. 'ql-script': '上标/下标',
  109. 'ql-underline': '下划线',
  110. 'ql-blockquote': '引用',
  111. 'ql-header': '标题',
  112. 'ql-indent': '缩进',
  113. 'ql-list': '列表',
  114. 'ql-align': '文本对齐',
  115. 'ql-direction': '文本方向',
  116. 'ql-code-block': '代码块',
  117. 'ql-formula': '公式',
  118. 'ql-image': '图片',
  119. 'ql-video': '视频',
  120. 'ql-clean': '清除字体样式',
  121. 'ql-upload': '文件'
  122. };
  123. export default {
  124. name: 'contentOperation',
  125. components: {
  126. quillEditor
  127. },
  128. data () {
  129. return {
  130. categoryList: [],
  131. type: this.$route.query.type,
  132. pageType: this.$route.query.pageType,
  133. organId: null,
  134. headers: {
  135. Authorization: getToken()
  136. },
  137. content: null,
  138. editorOption: {
  139. placeholder: '请输入内容',
  140. modules: {
  141. toolbar: {
  142. container: toolbarOptions,
  143. handlers: {
  144. 'image': function (value) {
  145. if (value) {
  146. // 调用iview图片上传
  147. document.querySelector('.ivu-upload .el-upload').click()
  148. } else {
  149. this.quill.format('image', false);
  150. }
  151. }
  152. }
  153. }
  154. }
  155. },
  156. form: {
  157. title: null,
  158. order: null,
  159. coverImage: null,
  160. linkUrl: vaildStudentUrl() + '/#/specialdetail',
  161. type: this.$route.query.type,
  162. status: 1,
  163. content: null
  164. },
  165. rules: {
  166. title: [{ required: true, message: '请输入标题', trigger: 'blur' },
  167. { min: 2, max: 30, message: '长度在 2 到 30 个字符', trigger: 'blur' }],
  168. linkUrl: [{ required: true, message: '请输入连接地址', trigger: 'blur' }],
  169. coverImage: [{ required: true, message: '请选择封面图', trigger: 'blur' }],
  170. content: [{ required: true, message: '请编辑内容', trigger: 'blur' }]
  171. },
  172. imageSize: null
  173. }
  174. },
  175. mounted () {
  176. this.getList()
  177. this.addQuillTitle()
  178. // this.form.type
  179. let tempTitle = {
  180. 1: "468px * 552px",
  181. 2: "456px * 288px",
  182. 3: "686px * 140px",
  183. 4: null
  184. }
  185. this.imageSize = tempTitle[this.form.type]
  186. },
  187. methods: {
  188. addQuillTitle () {
  189. const oToolBar = document.querySelector('.ql-toolbar'),
  190. aButton = oToolBar.querySelectorAll('button'),
  191. aSelect = oToolBar.querySelectorAll('select');
  192. aButton.forEach(function (item) {
  193. if (item.className === 'ql-script') {
  194. item.value === 'sub' ? item.title = '下标' : item.title = '上标';
  195. } else if (item.className === 'ql-indent') {
  196. item.value === '+1' ? item.title = '向右缩进' : item.title = '向左缩进';
  197. } else {
  198. item.title = titleConfig[item.classList[0]];
  199. }
  200. });
  201. aSelect.forEach(function (item) {
  202. item.parentNode.title = titleConfig[item.classList[0]];
  203. });
  204. },
  205. onSubmit (formName) {
  206. this.$refs[formName].validate((valid) => {
  207. if (valid) {
  208. if (this.pageType == 'create') {
  209. if (this.form.id) { // 判断有没有Id,如果有则删除
  210. delete this.form.id
  211. }
  212. // return false
  213. newsAdd(this.form).then(res => {
  214. this.messageTips('添加', res)
  215. })
  216. } else if (this.pageType == 'update') {
  217. newsUpdate(this.form).then(res => {
  218. this.messageTips('修改', res)
  219. })
  220. }
  221. } else {
  222. return false
  223. }
  224. })
  225. },
  226. messageTips (title, res) {
  227. if (res.code == 200) {
  228. this.$message.success(title + '成功')
  229. this.$router.push({
  230. path: '/contentManager/contentManager',
  231. query: {
  232. type: this.typeIndex(this.type)
  233. }
  234. })
  235. } else {
  236. this.$message.error(res.msg)
  237. }
  238. },
  239. onCancel () {
  240. this.$router.push({
  241. path: '/contentManager/contentManager',
  242. query: {
  243. type: this.typeIndex(this.type)
  244. }
  245. })
  246. },
  247. handleSuccess (res) {
  248. // 获取富文本组件实例
  249. let quill = this.editor
  250. // 如果上传成功
  251. if (res.code) {
  252. // 获取光标所在位置
  253. let length = quill.getSelection().index;
  254. // 插入图片,res为服务器返回的图片链接地址
  255. quill.insertEmbed(length, 'image', res.data.url)
  256. // 调整光标到最后
  257. quill.setSelection(length + 1)
  258. } else {
  259. // 提示信息,需引入Message
  260. this.$message.error('图片插入失败')
  261. }
  262. },
  263. onReSet (formName) {
  264. this.$refs[formName].resetFields()
  265. },
  266. getList () {
  267. if (this.pageType == 'create') return false
  268. newsQueryId({ id: this.$route.query.id }).then(res => {
  269. if (res.code == 200) {
  270. let result = res.data
  271. let form = this.form
  272. this.form = {
  273. id: result.id,
  274. title: result.title,
  275. order: result.order,
  276. coverImage: result.coverImage,
  277. linkUrl: result.linkUrl,
  278. type: result.type,
  279. status: result.status,
  280. content: result.content
  281. }
  282. }
  283. })
  284. },
  285. handleAvatarSuccess (res, file) {
  286. this.form.coverImage = res.data.url
  287. },
  288. beforeAvatarUpload (file) {
  289. const imageType = {
  290. 'image/png': true,
  291. 'image/jpeg': true
  292. }
  293. const isImage = imageType[file.type]
  294. const isLt2M = file.size / 1024 / 1024 < 2
  295. if (!isImage) {
  296. this.$message.error('只能上传图片格式!')
  297. }
  298. if (!isLt2M) {
  299. this.$message.error('上传头像图片大小不能超过 2MB!')
  300. }
  301. return isImage && isLt2M;
  302. },
  303. typeChange (type) {
  304. let tempTitle = {
  305. 1: "精彩活动",
  306. 2: "热门资讯",
  307. 3: "活动列表",
  308. 4: "专项训练"
  309. }
  310. return tempTitle[type]
  311. },
  312. typeIndex (type) {
  313. let tempTitle = {
  314. 3: 0,
  315. 1: 1,
  316. 2: 2,
  317. 4: 3
  318. }
  319. return tempTitle[type]
  320. },
  321. onEditorChange ({ quill, html, text }) {
  322. this.form.content = html
  323. }
  324. },
  325. computed: {
  326. editor () {
  327. return this.$refs.myQuillEditor.quill
  328. }
  329. },
  330. }
  331. </script>
  332. <style lang="scss" scoped>
  333. .m-container {
  334. min-width: 100%;
  335. }
  336. .el-input {
  337. width: 400px;
  338. }
  339. /deep/.ql-editor {
  340. min-height: 300px;
  341. }
  342. .el-button--primary {
  343. background: #14928a;
  344. border-color: #14928a;
  345. color: #fff;
  346. &:hover,
  347. &:active,
  348. &:focus {
  349. background: #14928a;
  350. border-color: #14928a;
  351. color: #fff;
  352. }
  353. }
  354. .el-row {
  355. margin-top: 40px;
  356. }
  357. .el-col {
  358. display: flex;
  359. align-items: center;
  360. margin-bottom: 20px;
  361. justify-content: flex-end;
  362. margin-right: 50%;
  363. }
  364. .el-input-group {
  365. width: 200px;
  366. margin: 0 20px;
  367. }
  368. /deep/.el-tree-node__content {
  369. height: 40px !important;
  370. }
  371. /deep/.avatar-uploader .el-upload {
  372. border: 1px dashed #d9d9d9;
  373. border-radius: 6px;
  374. cursor: pointer;
  375. position: relative;
  376. overflow: hidden;
  377. }
  378. .avatar-uploader .el-upload:hover {
  379. border-color: #409eff;
  380. }
  381. .avatar-uploader-icon {
  382. font-size: 28px;
  383. color: #8c939d;
  384. width: 120px;
  385. height: 120px;
  386. line-height: 120px;
  387. text-align: center;
  388. }
  389. .avatar {
  390. width: 120px;
  391. height: 120px;
  392. display: block;
  393. }
  394. .ivu-upload {
  395. display: none;
  396. }
  397. </style>