articleCreate.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. <template>
  2. <div class="app-container">
  3. <div class="common-card basic-information-box">
  4. <div class="basic-information-title">基本信息</div>
  5. <div class="basic-information-form">
  6. <a-form
  7. :form="form"
  8. :label-col="{ span: 6 }"
  9. :wrapper-col="{ span: 18 }"
  10. style="width: 515px"
  11. @submit="handleSubmit"
  12. >
  13. <a-form-item label="文章标题">
  14. <a-input
  15. placeholder="请输入文章标题"
  16. :maxLength="100"
  17. v-decorator="[
  18. 'name',
  19. {
  20. rules: [{ required: true, message: '请输入文章标题' }],
  21. },
  22. ]"
  23. />
  24. </a-form-item>
  25. <!-- <a-form-item label="文章描述">
  26. <a-textarea
  27. placeholder="请输入文章描述"
  28. :auto-size="{ minRows: 3, maxRows: 5 }"
  29. :maxLength="100"
  30. v-decorator="[
  31. 'description',
  32. {
  33. rules: [{ message: '请输入文章描述' }],
  34. initialValue: description,
  35. },
  36. ]"
  37. />
  38. </a-form-item> -->
  39. <a-form-item label="文章分类">
  40. <!-- 文章分类父类 -->
  41. <a-select
  42. v-decorator="[
  43. 'articleParentClass',
  44. {
  45. rules: [
  46. {
  47. required: optionType == 'create',
  48. message: '请选择文章分类父类',
  49. },
  50. ],
  51. initialValue: articleParentClass.name,
  52. },
  53. ]"
  54. @change="articleClassParentChange"
  55. >
  56. <a-select-option
  57. v-for="(item, index) in articleParentClassArr"
  58. :key="index"
  59. >{{ articleParentClassArr[index].name }}</a-select-option
  60. >
  61. </a-select>
  62. </a-form-item>
  63. <a-form-item label="文章子类">
  64. <!-- 文章分类子类 -->
  65. <a-select
  66. v-decorator="[
  67. 'articleChildClass',
  68. {
  69. rules: [
  70. {
  71. required: optionType == 'create',
  72. message: '请选择文章分类子类',
  73. },
  74. ],
  75. initialValue: articleChildClass.name,
  76. },
  77. ]"
  78. :disabled="!articleChildClass || !articleChildClass.id"
  79. @change="articleClassChildChange"
  80. >
  81. <a-select-option
  82. v-for="(item, index) in articleChildClassArr"
  83. :key="index"
  84. >{{ articleChildClassArr[index].name }}</a-select-option
  85. >
  86. </a-select>
  87. </a-form-item>
  88. <a-form-item label="工种类别">
  89. <a-select
  90. v-decorator="[
  91. 'engineerType',
  92. {
  93. rules: [{ required: true, message: '请选择工种' }],
  94. initialValue: engineerType.name,
  95. },
  96. ]"
  97. @change="engineerTypeChange"
  98. >
  99. <a-select-option
  100. v-for="(item, index) in engineerTypeArray"
  101. :key="index"
  102. >{{ engineerTypeArray[index].name }}</a-select-option
  103. >
  104. </a-select>
  105. </a-form-item>
  106. <a-form-item label="必学日期:">
  107. <!-- <a-date-picker
  108. :defaultValue="learnDate"
  109. @change="learnDateChoose"
  110. style="width:100%;"
  111. />-->
  112. <a-date-picker
  113. placeholder="请选择日期"
  114. @change="learnDateChoose"
  115. v-decorator="[
  116. 'learnDate',
  117. {
  118. initialValue: learnDate,
  119. },
  120. ]"
  121. style="width: 100%"
  122. />
  123. </a-form-item>
  124. <a-form-item v-show="false" :wrapper-col="{ span: 20, offset: 10 }">
  125. <a-button id="articleCreateSubmit" type="primary" html-type="submit"
  126. >提交</a-button
  127. >
  128. </a-form-item>
  129. </a-form>
  130. </div>
  131. </div>
  132. <div class="common-card a-card-margin-top">
  133. <div class="information-title">文章内容</div>
  134. <TinymceEditor v-model="content"></TinymceEditor>
  135. <div class="upload-oss-file-div">
  136. <div class="information-title">上传附件</div>
  137. <div>
  138. <a-upload
  139. :customRequest="uploadOssFile"
  140. :default-file-list="defaultFileList"
  141. :remove="removeOssFile"
  142. >
  143. <a-button> <a-icon type="upload" />点击上传 </a-button>
  144. </a-upload>
  145. </div>
  146. </div>
  147. <div class="submit-row">
  148. <a-button type="primary" @click="handleSubmitBtnFun">提交</a-button>
  149. <a-button :style="{ marginLeft: '160px' }" @click="preview"
  150. >预览</a-button
  151. >
  152. </div>
  153. </div>
  154. <!-- 预览弹出框 -->
  155. <a-drawer
  156. title
  157. placement="left"
  158. :closable="true"
  159. :visible="previewVisible"
  160. :bodyStyle="bodyStyle"
  161. @close="closepreview"
  162. width="30%"
  163. >
  164. <p class="p-content" v-html="content">{{ content }}</p>
  165. </a-drawer>
  166. <!-- <div class="company-info">
  167. <span>
  168. copyright © 浮游科技有限公司出品
  169. </span>
  170. </div>-->
  171. </div>
  172. </template>
  173. <script>
  174. const OSS = require("ali-oss");
  175. import {
  176. formatePathParams,
  177. formateStringDate,
  178. formateDateToString
  179. } from "@/filters";
  180. import TinymceEditor from "@/components/tinymce/TinymceEditor"; // 富文本编辑组件
  181. export default {
  182. name: "articleCreate",
  183. props: {},
  184. components: {
  185. TinymceEditor
  186. },
  187. data() {
  188. return {
  189. content: "",
  190. // 展示预览
  191. previewVisible: false,
  192. form: this.$form.createForm(this, { name: "articleCreate" }),
  193. articleParentClassArr: [],
  194. articleChildClassArr: [],
  195. engineerTypeArray: [],
  196. articleParentClass: {},
  197. articleChildClass: {},
  198. engineerType: "",
  199. learnDate: "",
  200. optionType: "",
  201. description: "",
  202. bodyStyle: {
  203. img: "{max-width:100%;}",
  204. color: "red"
  205. },
  206. defaultFileList: []
  207. };
  208. },
  209. created() {
  210. this.initDataFun(); //初始化数据
  211. },
  212. mounted() {},
  213. beforeDestroy() {},
  214. watch: {},
  215. computed: {},
  216. methods: {
  217. //初始化数据
  218. async initDataFun() {
  219. await this.getArticleParentClass();
  220. await this.getEngineersWork();
  221. let type = this.$route.query.type;
  222. this.optionType = type ? type : "create";
  223. // 判断是新增文章还是编辑文章
  224. if ("edit" === type) {
  225. console.log("---edit---");
  226. await this.getArticleContent();
  227. } else if ("create" === type) {
  228. console.log("---create---");
  229. }
  230. },
  231. // 查询文章分类父级
  232. getArticleParentClass() {
  233. this.$_http
  234. .get(this.$_API.INTERFACE_GET_CATEGORIES)
  235. .then(res => {
  236. this.articleParentClassArr = res.data;
  237. this.loading = false;
  238. })
  239. .catch(() => {
  240. this.loading = false;
  241. });
  242. },
  243. // 查询文章分类子集
  244. getArticleChildClass() {
  245. if (!this.articleParentClass.id) {
  246. return;
  247. }
  248. let pathParamsData = { categoryId: this.articleParentClass.id };
  249. this.$_http
  250. .get(
  251. formatePathParams(
  252. this.$_API.INTERFACE_GET_CATEGORIES_CATEGROYID,
  253. pathParamsData
  254. )
  255. )
  256. .then(res => {
  257. if (res && res.data.length !== 0) {
  258. this.articleChildClassArr = res.data;
  259. this.articleChildClass = this.articleChildClassArr[0];
  260. this.form.setFieldsValue({
  261. articleChildClass: this.articleChildClass.name
  262. });
  263. }
  264. this.loading = false;
  265. })
  266. .catch(() => {
  267. this.loading = false;
  268. });
  269. },
  270. // 查询工作类别
  271. async getEngineersWork() {
  272. await this.$_http
  273. .get(this.$_API.INTERFACE_GET_ENGINEERINGWORK_LIST)
  274. .then(res => {
  275. this.engineerTypeArray = [...res.data];
  276. this.engineerType = this.engineerTypeArray[0];
  277. });
  278. },
  279. // 文章分类父类变化
  280. articleClassParentChange(value) {
  281. this.articleParentClass = this.articleParentClassArr[value];
  282. // 子类选项清空
  283. this.articleChildClassArr = [];
  284. this.form.setFieldsValue({
  285. articleChildClass: ""
  286. });
  287. // 获取子类的值
  288. this.getArticleChildClass();
  289. },
  290. // 文章分类子类变化
  291. articleClassChildChange(value) {
  292. this.articleChildClass = this.articleChildClassArr[value];
  293. },
  294. // 工种变化
  295. engineerTypeChange(index) {
  296. this.engineerType = this.engineerTypeArray[index];
  297. },
  298. // 必学日期选择
  299. learnDateChoose(date, dateString) {
  300. this.learnDate = dateString;
  301. },
  302. handleSubmitBtnFun() {
  303. document.getElementById("articleCreateSubmit").click();
  304. },
  305. // 查询文章内容
  306. getArticleContent() {
  307. let pathParamsData = { materialId: this.$route.query.id };
  308. this.$_http
  309. .get(
  310. formatePathParams(this.$_API.INTERFACE_GET_MATERIALS, pathParamsData)
  311. )
  312. .then(res => {
  313. console.log("----" + JSON.stringify(res));
  314. this.initEditArticleForm(res.data);
  315. this.loading = false;
  316. })
  317. .catch(() => {
  318. this.loading = false;
  319. });
  320. },
  321. initEditArticleForm(item) {
  322. console.log("--------" + JSON.stringify(item));
  323. // 文章标题
  324. this.form.setFieldsValue({
  325. name: item.name
  326. });
  327. // 文章描述
  328. this.description = item.description ? item.description : "";
  329. // 文章分类-父类:
  330. this.articleParentClass = item.rootMaterialCategory;
  331. this.getArticleChildClass(); // 获取子类列表的值
  332. // 文章分类-子类
  333. this.articleChildClass = item.materialCategory;
  334. // 选中工种
  335. if (item.engineerTypes.length !== 0) {
  336. let engineerId = item.engineerTypes[0];
  337. for (let i = 0; i < this.engineerTypeArray.length; i++) {
  338. let element = this.engineerTypeArray[i];
  339. if (element.id === engineerId) {
  340. this.engineerTypeChange(i);
  341. }
  342. }
  343. }
  344. let learnDate = item.tags.length > 0 ? item.tags[0] : null;
  345. // 必学日期
  346. this.learnDate = learnDate ? formateStringDate(learnDate) : null;
  347. console.log("编辑初始化时间为YYYY-MM-DD", this.learnDate, learnDate);
  348. // 文章内容
  349. this.content = item.contents;
  350. // 附件内容
  351. item.links.forEach(element => {
  352. let upFile = {
  353. uid: this.getUid(),
  354. name: this.getUrlName(element),
  355. status: "done",
  356. url: element
  357. };
  358. this.defaultFileList.push(upFile);
  359. });
  360. console.log(this.defaultFileList);
  361. },
  362. // 截取路径名字
  363. getUrlName(url) {
  364. let strArr = url.split("/");
  365. console.log(strArr);
  366. let fileName = strArr[strArr.length - 1];
  367. console.log(fileName);
  368. fileName = decodeURIComponent(fileName);
  369. console.log(fileName);
  370. return fileName;
  371. },
  372. // 提交表单
  373. handleSubmit(e) {
  374. e.preventDefault();
  375. if ("create" === this.optionType) {
  376. console.log("创建文章");
  377. this.createArtical();
  378. } else if ("edit" === this.optionType) {
  379. console.log("更新文章");
  380. this.updateArtical();
  381. }
  382. },
  383. createArtical() {
  384. this.form.setFieldsValue({
  385. articleParentClass: this.articleParentClass.name
  386. });
  387. this.form.setFieldsValue({
  388. articleChildClass: this.articleChildClass.name
  389. });
  390. this.form.setFieldsValue({
  391. engineerType: this.engineerType.name
  392. });
  393. this.form.validateFields((err, values) => {
  394. if (!err) {
  395. // 新建文章
  396. let that = this;
  397. that.$confirm({
  398. title: "新建文章",
  399. content: `确认新建文章吗?`,
  400. okText: "确认",
  401. cancelText: "取消",
  402. onOk() {
  403. that.loading = true;
  404. let params = {
  405. categoryid: that.articleChildClass.id,
  406. engineertypeid: that.engineerType.id
  407. };
  408. let tag = formateDateToString(that.learnDate);
  409. let links = [];
  410. that.defaultFileList.forEach(element => {
  411. links.push(element.url);
  412. });
  413. let bodyParams = {
  414. name: values.name,
  415. description: values.description,
  416. type: "ARTICLE",
  417. contents: that.content,
  418. tags: tag ? [tag] : [],
  419. engineerTypes: [that.engineerType.id],
  420. links: links
  421. };
  422. that.$_http
  423. .post(that.$_API.INTERFACE_POST_ADMIN_MATERIALS, bodyParams, {
  424. params
  425. })
  426. .then(() => {
  427. that.$message.success("新建文章成功");
  428. });
  429. },
  430. onCancel() {}
  431. });
  432. }
  433. });
  434. },
  435. updateArtical() {
  436. let pathParamsData = { materialId: this.$route.query.id };
  437. this.form.validateFields((err, values) => {
  438. if (!err) {
  439. // 更新文章
  440. let that = this;
  441. that.$confirm({
  442. title: "更新文章",
  443. content: `确认更新文章吗?`,
  444. okText: "确认",
  445. cancelText: "取消",
  446. onOk() {
  447. that.loading = true;
  448. let params = {
  449. categoryid: that.articleChildClass.id,
  450. engineertypeid: that.engineerType.id
  451. };
  452. let tag = formateDateToString(that.learnDate);
  453. let links = [];
  454. that.defaultFileList.forEach(element => {
  455. links.push(element.url);
  456. });
  457. console.log(links);
  458. let bodyParams = {
  459. id: that.$route.query.id,
  460. name: values.name,
  461. description: values.description,
  462. type: "ARTICLE",
  463. contents: that.content,
  464. tags: tag ? [tag] : [],
  465. engineerTypes: [that.engineerType.id],
  466. links: links
  467. };
  468. console.log(
  469. "保存修改日期格式为YYYYMMDD",
  470. bodyParams.tags,
  471. that.learnDate
  472. );
  473. that.$_http
  474. .put(
  475. formatePathParams(
  476. that.$_API.INTERFACE_PUT_ADMIN_MATERIALS,
  477. pathParamsData
  478. ),
  479. bodyParams,
  480. {
  481. params
  482. }
  483. )
  484. .then(() => {
  485. that.$message.success("更新文章成功");
  486. });
  487. },
  488. onCancel() {}
  489. });
  490. }
  491. });
  492. },
  493. uploadOssFile(fileData) {
  494. let file = fileData.file;
  495. let that = this;
  496. let bucket = "jtxt-file-public";
  497. // let filetype =
  498. // ".pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx";
  499. let ossPath = "file/";
  500. that.$_http.get(that.$_API.INTERFACE_GET_ASSUME_OSS_WRITER).then(res => {
  501. console.log("--oss-writer--" + JSON.stringify(res));
  502. const client = new OSS({
  503. // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  504. region: "oss-cn-beijing",
  505. // 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
  506. accessKeyId: res.data.accessKeyId,
  507. accessKeySecret: res.data.accessKeySecret,
  508. // 从STS服务获取的安全令牌(SecurityToken)。
  509. stsToken: res.data.securityToken,
  510. // 填写Bucket名称。
  511. bucket: bucket
  512. });
  513. let fileName = new Date().getTime() + "_" + file.name;
  514. let options = {
  515. progress: function(p) {
  516. // 断点记录点。浏览器重启后无法直接继续上传,您需要手动触发上传操作。
  517. console.log("-----" + JSON.stringify(p));
  518. // console.log("-----" + JSON.stringify(checkpoint));
  519. },
  520. patrtSize: 1000 * 1024, // 设置分片大小
  521. timeout: 1000 * 60 * 10 // 超时时间
  522. };
  523. try {
  524. client
  525. .multipartUpload(ossPath + fileName, file, options)
  526. .then(res => {
  527. console.log(res);
  528. let fileUrl = res.res.requestUrls[0].split("?")[0];
  529. console.log(fileUrl);
  530. let upFile = {
  531. uid: this.getUid(),
  532. name: fileName,
  533. status: "done",
  534. url: fileUrl
  535. };
  536. this.defaultFileList.push(upFile);
  537. fileData.onSuccess();
  538. });
  539. } catch (e) {
  540. fileData.onError();
  541. console.error(e);
  542. }
  543. });
  544. },
  545. removeOssFile(file) {
  546. for (let i = 0; i < this.defaultFileList.length; i++) {
  547. let tmpFile = this.defaultFileList[i];
  548. if (tmpFile.uid === file.uid) {
  549. this.defaultFileList.splice(i, 1);
  550. return;
  551. }
  552. }
  553. },
  554. getUid() {
  555. let uid = "";
  556. for (let i = 0; i < 5; i++) {
  557. uid += Math.floor(Math.random() * 10);
  558. }
  559. return uid;
  560. },
  561. // 预览
  562. preview() {
  563. this.previewVisible = true;
  564. },
  565. // 关闭预览
  566. closepreview() {
  567. this.previewVisible = false;
  568. }
  569. }
  570. };
  571. </script>
  572. <style lang="less">
  573. .p-content {
  574. max-width: 100%;
  575. img {
  576. max-width: 100%;
  577. width: auto;
  578. height: auto;
  579. }
  580. }
  581. </style>
  582. <style lang="less" scoped>
  583. @import "~@/styles/common/variable.less";
  584. .app-container {
  585. .information-title {
  586. font-size: 18px;
  587. font-weight: bold;
  588. color: @mainColorBlack65;
  589. margin-bottom: @paddingMarginVal;
  590. }
  591. .submit-row {
  592. width: 100%;
  593. margin-top: 2 * @paddingMarginVal;
  594. padding: @paddingMarginVal 0 @navTopHight;
  595. display: flex;
  596. justify-content: center;
  597. }
  598. .upload-oss-file-div {
  599. margin: @paddingMarginVal 0;
  600. }
  601. }
  602. </style>