add_note.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. <template>
  2. <view class="add">
  3. <view class="share flexB">
  4. <view class="share_title">
  5. <text>第{{ params.season ? params.season : userInfo.season }}届大卫博士创业</text>
  6. <text v-if="type">{{ type == 1 ? '密训营' : '实战营' }}</text>
  7. <text v-else>{{ userInfo.season_type == 1 ? '密训营' : '实战营' }}</text>
  8. </view>
  9. <view class="flexS">
  10. <image src="../../static/imgs/color.png" @click="changeColor"></image>
  11. <view class="share_btn" @click="shareBtn">分享</view>
  12. </view>
  13. <view class="note_color" v-if="showColor">
  14. <image src="../../static/imgs/color_bg.png"></image>
  15. <view class="color_change">
  16. <view class="color_intr">
  17. <text>便签颜色</text>
  18. <text style="font-size:20rpx;color:#999;">(重要程度)</text>
  19. </view>
  20. <view class="colors">
  21. <view @click="choose(0)"><image :src="params.level == 0 ? '../../static/imgs/red_active.png' : '../../static/imgs/red.png'"></image></view>
  22. <view @click="choose(1)"><image :src="params.level == 1 ? '../../static/imgs/blue_active.png' : '../../static/imgs/blue.png'"></image></view>
  23. <view @click="choose(2)"><image :src="params.level == 2 ? '../../static/imgs/green_active.png' : '../../static/imgs/green.png'"></image></view>
  24. </view>
  25. </view>
  26. </view>
  27. </view>
  28. <view class="edit_note">
  29. <input type="text" placeholder="请输入便签标题(点击编辑)" placeholder-style="font-size:36rpx;font-weight:bold;color:#333;" v-model="params.title" maxlength="16" />
  30. <view class="icon" @click="format">
  31. <view :class="formats.bold ? 'ql-active' : ''" class="iconfont icon-zitijiacu" data-name="bold"></view>
  32. <view :class="formats.italic ? 'ql-active' : ''" class="iconfont icon-zitixieti" data-name="italic"></view>
  33. <view :class="formats.underline ? 'ql-active' : ''" class="iconfont icon-zitixiahuaxian" data-name="underline"></view>
  34. <view :class="formats.align === 'left' ? 'ql-active' : ''" class="iconfont icon-zuoduiqi" data-name="align" data-value="left"></view>
  35. <view :class="formats.align === 'center' ? 'ql-active' : ''" class="iconfont icon-juzhongduiqi" data-name="align" data-value="center"></view>
  36. <view :class="formats.align === 'right' ? 'ql-active' : ''" class="iconfont icon-youduiqi" data-name="align" data-value="right"></view>
  37. <view :class="formats.align === 'justify' ? 'ql-active' : ''" class="iconfont icon-zuoyouduiqi" data-name="align" data-value="justify"></view>
  38. </view>
  39. <editor id="editor" class="ql-container" placeholder="此时此刻你想写点什么呢..." @ready="onEditorReady" @input="getText" @statuschange="onStatusChange"></editor>
  40. </view>
  41. <view class="add_btn" @click.stop="showBtn = !showBtn">
  42. <view class="add_btn_active" v-if="showBtn == true">
  43. <image src="../../static/imgs/add__btn_active.png" class="active_btn"></image>
  44. <view class="opera flexCC"><image src="../../static/imgs/add_img.png" style="margin-top:15rpx;" @click="insertImage"></image></view>
  45. </view>
  46. <image src="../../static/imgs/add.png" v-else></image>
  47. </view>
  48. <view class="bottom">
  49. <view class="flexCC" @click="skipNote(0)">保存</view>
  50. <view class="flexCC" @click="skipNote(1)">发布</view>
  51. </view>
  52. <view class="long_img flexCC" v-if="showImg">
  53. <view class="flexCC">
  54. <view class="img_box">
  55. <text class="iconfont iconguanbi" @click="showImg = false"></text>
  56. <image :src="longImage" @click="imgPreview" mode="aspectFit"></image>
  57. </view>
  58. <view class="img_btn" @click="saveImg">保存图片</view>
  59. </view>
  60. </view>
  61. </view>
  62. </template>
  63. <script>
  64. import { upLoad, addNote, showNote, getLongImg } from '../../api/note.js';
  65. import request from '../../utiils/request.js';
  66. import { base64src } from '../../utiils/base64src.js';
  67. export default {
  68. data() {
  69. return {
  70. formats: {}, //editor样式
  71. showBtn: false,
  72. showColor: false, //显示便签颜色
  73. showImg: false, //是否显示长图
  74. type: '', //实战营还是实训营
  75. userInfo: '', //用户信息
  76. params: {
  77. id: '', //便签id
  78. title: '', //便签标题
  79. content: '', //便签内容带标签
  80. level: 0, //便签重要程度
  81. cover_url: '', //封面图片
  82. summary: '', //便签简介
  83. body: '' //便签内容纯文本
  84. },
  85. longImage: '' //保存的长图
  86. };
  87. },
  88. onLoad(options) {
  89. if (options.id) {
  90. this.params.id = options.id;
  91. this.type = options.type;
  92. }
  93. },
  94. onShow() {
  95. this.userInfo = uni.getStorageSync('userInfo');
  96. },
  97. methods: {
  98. //点击长图放大
  99. imgPreview() {
  100. uni.previewImage({
  101. cur: this.longImage,
  102. urls: [this.longImage]
  103. });
  104. },
  105. //保存图片按钮
  106. saveImg() {
  107. uni.saveImageToPhotosAlbum({
  108. filePath: this.longImage,
  109. success: res => {
  110. uni.showModal({
  111. content: '保存图片成功',
  112. showCancel: false
  113. });
  114. this.showImg = false;
  115. },
  116. fail: err => {
  117. if (err.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
  118. uni.showModal({
  119. title: '提示',
  120. content: '您好,请先授权,再保存此图片。',
  121. showCancel: false,
  122. success: res => {
  123. if (res.confirm) {
  124. uni.openSetting({
  125. success: res => {
  126. console.log(res);
  127. if (res.authSetting['scope.writePhotosAlbum']) {
  128. uni.showModal({
  129. content: '请重新长按保存图片',
  130. showCancel: false
  131. });
  132. } else {
  133. uni.showModal({
  134. content: '您拒绝了保存到相册权限',
  135. showCancel: false
  136. });
  137. }
  138. },
  139. fail: err => {
  140. uni.showModal({
  141. content: '手动打开相册权限失败',
  142. showCancel: false
  143. });
  144. }
  145. });
  146. }
  147. }
  148. });
  149. }
  150. },
  151. complete() {
  152. uni.hideLoading();
  153. }
  154. });
  155. },
  156. // 修改便签样式
  157. format(e) {
  158. let { name, value } = e.target.dataset;
  159. if (!name) return;
  160. this.editorCtx.format(name, value);
  161. },
  162. onStatusChange(e) {
  163. const formats = e.detail;
  164. this.formats = formats;
  165. },
  166. /*
  167. * 初始化编辑器 如果有内容回显,没有内容显示为空
  168. */
  169. onEditorReady() {
  170. let that = this;
  171. uni.createSelectorQuery()
  172. .select('#editor')
  173. .context(res => {
  174. console.log(res.context);
  175. this.editorCtx = res.context;
  176. if (!res) return;
  177. //便签列表进来回显
  178. if (this.params.id) {
  179. showNote({ id: this.params.id }).then(res => {
  180. if (res.code == 200) {
  181. this.params = res.data;
  182. this.editorCtx.setContents({
  183. html: res.data.content,
  184. success: res => {
  185. console.log('渲染成功');
  186. },
  187. fail: res => {
  188. console.log('渲染失败');
  189. }
  190. });
  191. } else {
  192. uni.showModal({
  193. content: res.message || '获取内容失败',
  194. showCancel: false
  195. });
  196. }
  197. });
  198. }
  199. })
  200. .exec();
  201. },
  202. toJSON() {},
  203. /*
  204. * 获取编辑器内容输入的内容
  205. */
  206. getText(e) {
  207. let ops = e.target.delta.ops;
  208. let img = ops.map(i => {
  209. if (i.insert.image) {
  210. return i.insert.image;
  211. }
  212. });
  213. let img1 = img.filter(i => {
  214. return i != undefined;
  215. });
  216. this.params.cover_url = img1[0] ? img1[0] : '';
  217. this.params.summary = e.detail.text.substring(0, 40) + '...';
  218. this.params.content = e.detail.html;
  219. this.params.body = e.detail.text;
  220. },
  221. //打开标签选择页面
  222. changeColor() {
  223. this.showColor = !this.showColor;
  224. },
  225. //选择标签颜色
  226. choose(tabType) {
  227. this.params.level = tabType;
  228. this.showColor = false;
  229. },
  230. /*
  231. * 新建、修改标签
  232. * @params id 当修改是带着id,添加时不带
  233. * @params title 便签标题
  234. * @params content 便签内容
  235. * @params level 便签重要级
  236. * @params cover_url 封面
  237. * @params summary 便签简介
  238. * @params status 便签状态
  239. * desc isShare 是否点击了分享按钮
  240. */
  241. skipNote(type, isShare) {
  242. if (!this.params.title) {
  243. uni.showModal({
  244. content: '便签标题不能为空!',
  245. showCancel: false
  246. });
  247. return false;
  248. }
  249. //type 0 保存 type 1 发布
  250. if (type == 1 && !this.userInfo.sign_type) {
  251. //只有报名本赛季的才可以发布便签
  252. uni.showModal({
  253. content: '您本赛季暂未报名',
  254. showCancel: false
  255. });
  256. return false;
  257. }
  258. let data = {};
  259. let { id, title, content, level, cover_url, summary, body } = this.params;
  260. if (this.params.id) {
  261. data = {
  262. id,
  263. title,
  264. content,
  265. level,
  266. cover_url,
  267. summary,
  268. status: type,
  269. body
  270. };
  271. } else {
  272. data = {
  273. title,
  274. content,
  275. level,
  276. cover_url,
  277. summary,
  278. status: type,
  279. body
  280. };
  281. }
  282. addNote(data).then(res => {
  283. if (res.code == 200) {
  284. if (isShare == true) {
  285. uni.showLoading({
  286. title: '生成图片中....'
  287. });
  288. uni.request({
  289. url: 'http://192.168.0.6:8030/api' + '/note/note_share',
  290. method: 'get',
  291. data: { id: this.params.id },
  292. header: {
  293. 'content-type': 'application/x-www-form-urlencoded',
  294. Authorization: 'bearer' + ' ' + uni.getStorageSync('token')
  295. },
  296. responseType: 'arraybuffer',
  297. success: res => {
  298. let url = 'data:image/png;base64,' + wx.arrayBufferToBase64(res.data);
  299. base64src(url, res => {
  300. this.longImage = res;
  301. });
  302. this.showImg = true;
  303. uni.hideLoading();
  304. },
  305. fail: err => {
  306. uni.showToast({
  307. title: '生成图片失败',
  308. showCancel: false
  309. });
  310. }
  311. });
  312. } else {
  313. uni.showModal({
  314. content: type == 0 ? '保存成功' : '发布成功',
  315. showCancel: false,
  316. success: res => {
  317. if (res.confirm) {
  318. if (type == 0) {
  319. uni.redirectTo({
  320. url: '../note_pad/note_pad?curTab=' + 0
  321. });
  322. } else {
  323. uni.redirectTo({
  324. url: '../note_pad/note_pad?curTab=' + 1
  325. });
  326. }
  327. }
  328. }
  329. });
  330. }
  331. } else {
  332. uni.showModal({
  333. content: res.message || '添加失败',
  334. showCancel: false
  335. });
  336. }
  337. });
  338. },
  339. //点击分享生成图片
  340. shareBtn() {
  341. let that = this;
  342. if (!that.params.id) {
  343. uni.showModal({
  344. content: '保存或发布之后才能分享',
  345. showCancel: false
  346. });
  347. return false;
  348. }
  349. let type = that.params.status.toString();
  350. if (type) {
  351. that.skipNote(Number(type), true);
  352. }
  353. },
  354. //插入图片(一次只能插入一张)
  355. insertImage() {
  356. const that = this;
  357. wx.chooseImage({
  358. count: 1,
  359. success: res => {
  360. uni.showLoading({
  361. title: '图片上传中...'
  362. });
  363. uni.uploadFile({
  364. url: 'http://192.168.0.6:8030/api' + '/note/upload_img',
  365. filePath: res.tempFilePaths[0],
  366. name: 'img',
  367. formData: '',
  368. header: {
  369. 'content-type': 'application/x-www-form-urlencoded',
  370. Authorization: 'bearer' + ' ' + uni.getStorageSync('token')
  371. },
  372. success: res => {
  373. uni.hideLoading();
  374. var data = JSON.parse(res.data);
  375. that.editorCtx.insertImage({
  376. src: data.data.img,
  377. data: {
  378. id: 'abcd',
  379. role: 'god'
  380. },
  381. width: '100%',
  382. extClass: 'center',
  383. success: res => {
  384. console.log('insert image success');
  385. }
  386. });
  387. },
  388. fail: err => {
  389. uni.showModal({
  390. content: res.message,
  391. showCancel: false
  392. });
  393. }
  394. });
  395. }
  396. });
  397. }
  398. }
  399. };
  400. </script>
  401. <style lang="scss">
  402. .long_img {
  403. position: fixed;
  404. top: 0;
  405. bottom: 0;
  406. left: 0;
  407. right: 0;
  408. z-index: 999;
  409. width: 100vw;
  410. height: 100vh;
  411. background-color: rgba(0, 0, 0, 0.8);
  412. > view {
  413. width: 650rpx;
  414. margin: 0 auto;
  415. .img_box {
  416. width: 650rpx;
  417. height: 1000rpx;
  418. border-radius: 24rpx;
  419. margin-bottom: 40rpx;
  420. .iconfont {
  421. font-size: 54rpx;
  422. color: #999;
  423. position: fixed;
  424. right: 76rpx;
  425. top: 5rpx;
  426. }
  427. image {
  428. width: 100%;
  429. height: 100%;
  430. border-radius: 24rpx;
  431. }
  432. }
  433. .img_btn {
  434. width: 256rpx;
  435. text-align: center;
  436. height: 88rpx;
  437. line-height: 88rpx;
  438. background: linear-gradient(93deg, #f97c55 0%, #f44545 100%);
  439. opacity: 1;
  440. border-radius: 44rpx;
  441. color: #fff;
  442. }
  443. }
  444. }
  445. .ql-active {
  446. color: #06c;
  447. }
  448. button {
  449. margin-top: 10px;
  450. }
  451. .current {
  452. font-size: 36rpx;
  453. font-weight: bold;
  454. color: #fff;
  455. image {
  456. width: 50rpx;
  457. height: 50rpx;
  458. vertical-align: -13rpx;
  459. }
  460. }
  461. .add {
  462. width: 100%;
  463. height: 100%;
  464. position: relative;
  465. }
  466. .share {
  467. width: 100%;
  468. height: 88rpx;
  469. padding: 0 30rpx;
  470. box-sizing: border-box;
  471. background-color: #f44545;
  472. color: #fff;
  473. position: relative;
  474. image {
  475. width: 45rpx;
  476. height: 39rpx;
  477. margin-right: 15rpx;
  478. }
  479. .share_title {
  480. font-size: 28rpx;
  481. color: #fff;
  482. }
  483. .share_btn {
  484. width: 92rpx;
  485. text-align: center;
  486. height: 46rpx;
  487. line-height: 46rpx;
  488. background: #fff;
  489. border-radius: 8rpx;
  490. font-size: 28rpx;
  491. color: #f44545;
  492. }
  493. .note_color {
  494. position: fixed;
  495. top: 83rpx;
  496. right: 100rpx;
  497. z-index: 9999;
  498. image {
  499. width: 292rpx;
  500. height: 166rpx;
  501. }
  502. .color_change {
  503. position: absolute;
  504. top: 51rpx;
  505. left: 33rpx;
  506. width: 80%;
  507. .color_intr {
  508. font-size: 28rpx;
  509. color: #333;
  510. }
  511. .colors {
  512. display: flex;
  513. justify-content: space-around;
  514. align-items: center;
  515. margin-top: 17rpx;
  516. image {
  517. width: 32rpx;
  518. height: 32rpx;
  519. }
  520. }
  521. }
  522. }
  523. }
  524. .edit_note {
  525. .icon {
  526. width: 100%;
  527. display: flex;
  528. justify-content: space-around;
  529. align-items: center;
  530. margin: 20rpx 0;
  531. .iconfont {
  532. font-size: 40rpx;
  533. }
  534. }
  535. input {
  536. width: 100%;
  537. text-align: center;
  538. font-size: 32rpx;
  539. font-weight: bold;
  540. color: #333;
  541. padding: 15rpx 0;
  542. }
  543. #editor {
  544. width: 90%;
  545. margin: 0 auto;
  546. height: 70vh;
  547. font-size: 28rpx;
  548. line-height: 1.5;
  549. }
  550. }
  551. .add_btn {
  552. position: absolute;
  553. bottom: 15vh;
  554. left: 75%;
  555. image {
  556. width: 150rpx;
  557. height: 150rpx;
  558. }
  559. }
  560. .add_btn_active {
  561. width: 148rpx;
  562. height: 254rpx;
  563. .active_btn {
  564. width: 100%;
  565. height: 100%;
  566. }
  567. .opera {
  568. position: absolute;
  569. top: -103rpx;
  570. left: 38rpx;
  571. height: 342rpx;
  572. image {
  573. width: 72rpx;
  574. height: 72rpx;
  575. }
  576. }
  577. }
  578. .bottom {
  579. width: 100%;
  580. height: 88rpx;
  581. display: flex;
  582. align-items: center;
  583. background: #f44545;
  584. position: fixed;
  585. bottom: 0;
  586. left: 0;
  587. view:first-child {
  588. border-right: 1rpx solid #fff;
  589. }
  590. view {
  591. height: 100%;
  592. width: 50%;
  593. color: #fff;
  594. font-size: 28rpx;
  595. }
  596. }
  597. // .long_img {
  598. // position: fixed;
  599. // width: 100%;
  600. // // height: 100%;
  601. // top: 0;
  602. // left: 0;
  603. // background: rgba(0, 0, 0, 0.6);
  604. // }
  605. </style>