Vue项目中集成TinyMCE富文本编辑器(图片批量上传等)
TinyMCE富文本在Vue中的使用
关于TinyMCE
实现效果
安装使用TinyMCE
第一步
第二步
1.官网申请Your Tiny API Key,并且配置访问域名:
2.使用css隐藏(这个就不讲了,不推荐使用)
3.全部由本地加载(推荐)
第三步(汉化包)
第四步(封装组件)
1.动态引入JS文件
2.自定义图片上传逻辑
3.上传图片文件路径变为相对路径
4.图片批量上传(非官方插件的使用)
总结
关于TinyMCE
TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有:UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。因为项目原因,本文章是在Vue2中封装TinyMce富文本组件。
实现效果
基本效果如图,还可以自己替换图标等,我这里额外引入了图片批量上传插件,后面会讲如何使引用且使用插件,需要使用其他插件的也是一个套路。
安装使用TinyMCE
第一步
//安装tinymce
yarn add tinymce@5.10.0 -S
//安装tinymce-vue
yarn add @tinymce/tinymce-vue@3.0.1 -S
第二步
在使用TinyMCE过程中,会出现如上图提示,是因为TinyMCE官方需要apiKey,解决办法有三种:
1.官网申请Your Tiny API Key,并且配置访问域名:
TinyMCE官网地址https://www.tiny.cloud/
注册登录后拿到apiKey
然后配置域名
具体代码中的使用在后面。
2.使用css隐藏(这个就不讲了,不推荐使用)
3.全部由本地加载(推荐)
在node_modules中找到tinymce文件夹(注意不是@tinymce文件夹)
然后将文件移入到pubilc/tinymce文件夹中
网上大部分相关教程都是在index.html中引入,如下:
但我在项目中出现,当浏览器左上角强制刷新页面时,可能会出现组件找不到tinymce.min.js文件问题,如下:
看报错,很明显引入时机有问题,那就只能在每次使用组件时动态去引入tinymce.min.js文件了,具体代码在后文。
第三步(汉化包)
在public下新建/lang/zh_CN.js 如下:
文件内容如下(粘贴复制就可):
tinymce.addI18n("zh_CN", {Redo: "\u91cd\u505a",Undo: "\u64a4\u9500",Cut: "\u526a\u5207",Copy: "\u590d\u5236",Paste: "\u7c98\u8d34","Select all": "\u5168\u9009","New document": "\u65b0\u6587\u4ef6",Ok: "\u786e\u5b9a",Cancel: "\u53d6\u6d88","Visual aids": "\u7f51\u683c\u7ebf",Bold: "\u7c97\u4f53",Italic: "\u659c\u4f53",Underline: "\u4e0b\u5212\u7ebf",Strikethrough: "\u5220\u9664\u7ebf",Superscript: "\u4e0a\u6807",Subscript: "\u4e0b\u6807","Clear formatting": "\u6e05\u9664\u683c\u5f0f","Align left": "\u5de6\u8fb9\u5bf9\u9f50","Align center": "\u4e2d\u95f4\u5bf9\u9f50","Align right": "\u53f3\u8fb9\u5bf9\u9f50",Justify: "\u4e24\u7aef\u5bf9\u9f50","Bullet list": "\u9879\u76ee\u7b26\u53f7","Numbered list": "\u7f16\u53f7\u5217\u8868","Decrease indent": "\u51cf\u5c11\u7f29\u8fdb","Increase indent": "\u589e\u52a0\u7f29\u8fdb",Close: "\u5173\u95ed",Formats: "\u683c\u5f0f","Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":"\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X/C/V\u7b49\u5feb\u6377\u952e\u3002",Headers: "\u6807\u9898","Header 1": "\u6807\u98981","Header 2": "\u6807\u98982","Header 3": "\u6807\u98983","Header 4": "\u6807\u98984","Header 5": "\u6807\u98985","Header 6": "\u6807\u98986",Headings: "\u6807\u9898","Heading 1": "\u6807\u98981","Heading 2": "\u6807\u98982","Heading 3": "\u6807\u98983","Heading 4": "\u6807\u98984","Heading 5": "\u6807\u98985","Heading 6": "\u6807\u98986",Preformatted: "\u9884\u5148\u683c\u5f0f\u5316\u7684",Div: "Div",Pre: "Pre",Code: "\u4ee3\u7801",Paragraph: "\u6bb5\u843d",Blockquote: "\u5f15\u6587\u533a\u5757",Inline: "\u6587\u672c",Blocks: "\u57fa\u5757","Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.":"\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",Fonts: "\u5b57\u4f53","Font Sizes": "\u5b57\u53f7",Class: "\u7c7b\u578b","Browse for an image": "\u6d4f\u89c8\u56fe\u50cf",OR: "\u6216","Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64",Upload: "\u4e0a\u4f20",Block: "\u5757",Align: "\u5bf9\u9f50",Default: "\u9ed8\u8ba4",Circle: "\u7a7a\u5fc3\u5706",Disc: "\u5b9e\u5fc3\u5706",Square: "\u65b9\u5757","Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd","Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd","Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd","Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd","Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd","Anchor...": "\u951a\u70b9...",Name: "\u540d\u79f0",Id: "\u6807\u8bc6\u7b26","Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.":"\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002","You have unsaved changes are you sure you want to navigate away?":"\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f","Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f","Special character...": "\u7279\u6b8a\u5b57\u7b26...","Source code": "\u6e90\u4ee3\u7801","Insert/Edit code sample":"\u63d2\u5165/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",Language: "\u8bed\u8a00","Code sample...": "\u793a\u4f8b\u4ee3\u7801...","Color Picker": "\u9009\u8272\u5668",R: "R",G: "G",B: "B","Left to right": "\u4ece\u5de6\u5230\u53f3","Right to left": "\u4ece\u53f3\u5230\u5de6",Emoticons: "\u8868\u60c5","Emoticons...": "\u8868\u60c5\u7b26\u53f7...","Metadata and Document Properties":"\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027",Title: "\u6807\u9898",Keywords: "\u5173\u952e\u8bcd",Description: "\u63cf\u8ff0",Robots: "\u673a\u5668\u4eba",Author: "\u4f5c\u8005",Encoding: "\u7f16\u7801",Fullscreen: "\u5168\u5c4f",Action: "\u64cd\u4f5c",Shortcut: "\u5feb\u6377\u952e",Help: "\u5e2e\u52a9",Address: "\u5730\u5740","Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f","Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f","Focus to element path":"\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84","Focus to contextual toolbar":"\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355","Insert link (if link plugin activated)":"\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Save (if save plugin activated)":"\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Find (if searchreplace plugin activated)":"\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):","Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a","Learn more...": "\u4e86\u89e3\u66f4\u591a...","You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}",Plugins: "\u63d2\u4ef6","Handy Shortcuts": "\u5feb\u6377\u952e","Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf","Insert/edit image": "\u63d2\u5165/\u7f16\u8f91\u56fe\u7247","Alternative description": "\u66ff\u4ee3\u63cf\u8ff0",Accessibility: "\u8f85\u52a9\u529f\u80fd","Image is decorative": "\u56fe\u50cf\u662f\u88c5\u9970\u6027\u7684",Source: "\u5730\u5740",Dimensions: "\u5927\u5c0f","Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",General: "\u666e\u901a",Advanced: "\u9ad8\u7ea7",Style: "\u6837\u5f0f","Vertical space": "\u5782\u76f4\u8fb9\u8ddd","Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",Border: "\u8fb9\u6846","Insert image": "\u63d2\u5165\u56fe\u7247","Image...": "\u56fe\u7247...","Image list": "\u56fe\u7247\u5217\u8868","Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c","Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c","Flip vertically": "\u5782\u76f4\u7ffb\u8f6c","Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c","Edit image": "\u7f16\u8f91\u56fe\u7247","Image options": "\u56fe\u7247\u9009\u9879","Zoom in": "\u653e\u5927","Zoom out": "\u7f29\u5c0f",Crop: "\u88c1\u526a",Resize: "\u8c03\u6574\u5927\u5c0f",Orientation: "\u65b9\u5411",Brightness: "\u4eae\u5ea6",Sharpen: "\u9510\u5316",Contrast: "\u5bf9\u6bd4\u5ea6","Color levels": "\u989c\u8272\u5c42\u6b21",Gamma: "\u4f3d\u9a6c\u503c",Invert: "\u53cd\u8f6c",Apply: "\u5e94\u7528",Back: "\u540e\u9000","Insert date/time": "\u63d2\u5165\u65e5\u671f/\u65f6\u95f4","Date/time": "\u65e5\u671f/\u65f6\u95f4","Insert/edit link": "\u63d2\u5165/\u7f16\u8f91\u94fe\u63a5","Text to display": "\u663e\u793a\u6587\u5b57",Url: "\u5730\u5740","Open link in...": "\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...","Current window": "\u5f53\u524d\u7a97\u53e3",None: "\u65e0","New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00","Open link": "\u6253\u5f00\u94fe\u63a5","Remove link": "\u5220\u9664\u94fe\u63a5",Anchors: "\u951a\u70b9","Link...": "\u94fe\u63a5...","Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5","The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required http:// prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp://:\u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required https:// prefix?":"\u60a8\u8f93\u5165\u7684 URL \u4f3c\u4e4e\u662f\u4e00\u4e2a\u5916\u90e8\u94fe\u63a5\u3002\u60a8\u60f3\u6dfb\u52a0\u6240\u9700\u7684 https:// \u524d\u7f00\u5417\uff1f","Link list": "\u94fe\u63a5\u5217\u8868","Insert video": "\u63d2\u5165\u89c6\u9891","Insert/edit video": "\u63d2\u5165/\u7f16\u8f91\u89c6\u9891","Insert/edit media": "\u63d2\u5165/\u7f16\u8f91\u5a92\u4f53","Alternative source": "\u955c\u50cf","Alternative source URL": "\u66ff\u4ee3\u6765\u6e90\u7f51\u5740","Media poster (Image URL)": "\u5c01\u9762(\u56fe\u7247\u5730\u5740)","Paste your embed code below:":"\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",Embed: "\u5185\u5d4c","Media...": "\u591a\u5a92\u4f53...","Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c","Page break": "\u5206\u9875\u7b26","Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",Preview: "\u9884\u89c8","Print...": "\u6253\u5370...",Save: "\u4fdd\u5b58",Find: "\u67e5\u627e","Replace with": "\u66ff\u6362\u4e3a",Replace: "\u66ff\u6362","Replace all": "\u5168\u90e8\u66ff\u6362",Previous: "\u4e0a\u4e00\u4e2a",Next: "\u4e0b\u4e00\u4e2a","Find and Replace": "\u67e5\u627e\u548c\u66ff\u6362","Find and replace...": "\u67e5\u627e\u5e76\u66ff\u6362...","Could not find the specified string.":"\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.","Match case": "\u533a\u5206\u5927\u5c0f\u5199","Find whole words only": "\u5168\u5b57\u5339\u914d","Find in selection": "\u5728\u9009\u533a\u4e2d\u67e5\u627e",Spellcheck: "\u62fc\u5199\u68c0\u67e5","Spellcheck Language": "\u62fc\u5199\u68c0\u67e5\u8bed\u8a00","No misspellings found.": "\u6ca1\u6709\u53d1\u73b0\u62fc\u5199\u9519\u8bef",Ignore: "\u5ffd\u7565","Ignore all": "\u5168\u90e8\u5ffd\u7565",Finish: "\u5b8c\u6210","Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178","Insert table": "\u63d2\u5165\u8868\u683c","Table properties": "\u8868\u683c\u5c5e\u6027","Delete table": "\u5220\u9664\u8868\u683c",Cell: "\u5355\u5143\u683c",Row: "\u884c",Column: "\u5217","Cell properties": "\u5355\u5143\u683c\u5c5e\u6027","Merge cells": "\u5408\u5e76\u5355\u5143\u683c","Split cell": "\u62c6\u5206\u5355\u5143\u683c","Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165","Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165","Delete row": "\u5220\u9664\u884c","Row properties": "\u884c\u5c5e\u6027","Cut row": "\u526a\u5207\u884c","Copy row": "\u590d\u5236\u884c","Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9","Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9","Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165","Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165","Delete column": "\u5220\u9664\u5217",Cols: "\u5217",Rows: "\u884c",Width: "\u5bbd",Height: "\u9ad8","Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd","Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",Caption: "\u6807\u9898","Show caption": "\u663e\u793a\u6807\u9898",Left: "\u5de6\u5bf9\u9f50",Center: "\u5c45\u4e2d",Right: "\u53f3\u5bf9\u9f50","Cell type": "\u5355\u5143\u683c\u7c7b\u578b",Scope: "\u8303\u56f4",Alignment: "\u5bf9\u9f50\u65b9\u5f0f","H Align": "\u6c34\u5e73\u5bf9\u9f50","V Align": "\u5782\u76f4\u5bf9\u9f50",Top: "\u9876\u90e8\u5bf9\u9f50",Middle: "\u5782\u76f4\u5c45\u4e2d",Bottom: "\u5e95\u90e8\u5bf9\u9f50","Header cell": "\u8868\u5934\u5355\u5143\u683c","Row group": "\u884c\u7ec4","Column group": "\u5217\u7ec4","Row type": "\u884c\u7c7b\u578b",Header: "\u8868\u5934",Body: "\u8868\u4f53",Footer: "\u8868\u5c3e","Border color": "\u8fb9\u6846\u989c\u8272","Insert template...": "\u63d2\u5165\u6a21\u677f...",Templates: "\u6a21\u677f",Template: "\u6a21\u677f","Text color": "\u6587\u5b57\u989c\u8272","Background color": "\u80cc\u666f\u8272","Custom...": "\u81ea\u5b9a\u4e49...","Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272","No color": "\u65e0","Remove color": "\u79fb\u9664\u989c\u8272","Table of Contents": "\u5185\u5bb9\u5217\u8868","Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846","Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26","Word count": "\u5b57\u6570",Count: "\u8ba1\u6570",Document: "\u6587\u6863",Selection: "\u9009\u62e9",Words: "\u5355\u8bcd","Words: {0}": "\u5b57\u6570\uff1a{0}","{0} words": "{0} \u5b57",File: "\u6587\u4ef6",Edit: "\u7f16\u8f91",Insert: "\u63d2\u5165",View: "\u89c6\u56fe",Format: "\u683c\u5f0f",Table: "\u8868\u683c",Tools: "\u5de5\u5177","Powered by {0}": "\u7531{0}\u9a71\u52a8","Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help":"\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9","Image title": "\u56fe\u7247\u6807\u9898","Border width": "\u8fb9\u6846\u5bbd\u5ea6","Border style": "\u8fb9\u6846\u6837\u5f0f",Error: "\u9519\u8bef",Warn: "\u8b66\u544a",Valid: "\u6709\u6548","To open the popup, press Shift+Enter":"\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846","Rich Text Area. Press ALT-0 for help.":"\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002","System Font": "\u7cfb\u7edf\u5b57\u4f53","Failed to upload image: {0}": "\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}","Failed to load plugin: {0} from url {1}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}","Failed to load plugin url: {0}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}","Failed to initialize plugin: {0}":"\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}",example: "\u793a\u4f8b",Search: "\u641c\u7d22",All: "\u5168\u90e8",Currency: "\u8d27\u5e01",Text: "\u6587\u5b57",Quotations: "\u5f15\u7528",Mathematical: "\u6570\u5b66","Extended Latin": "\u62c9\u4e01\u8bed\u6269\u5145",Symbols: "\u7b26\u53f7",Arrows: "\u7bad\u5934","User Defined": "\u81ea\u5b9a\u4e49","dollar sign": "\u7f8e\u5143\u7b26\u53f7","currency sign": "\u8d27\u5e01\u7b26\u53f7","euro-currency sign": "\u6b27\u5143\u7b26\u53f7","colon sign": "\u5192\u53f7","cruzeiro sign": "\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7","french franc sign": "\u6cd5\u90ce\u7b26\u53f7","lira sign": "\u91cc\u62c9\u7b26\u53f7","mill sign": "\u5bc6\u5c14\u7b26\u53f7","naira sign": "\u5948\u62c9\u7b26\u53f7","peseta sign": "\u6bd4\u585e\u5854\u7b26\u53f7","rupee sign": "\u5362\u6bd4\u7b26\u53f7","won sign": "\u97e9\u5143\u7b26\u53f7","new sheqel sign": "\u65b0\u8c22\u514b\u5c14\u7b26\u53f7","dong sign": "\u8d8a\u5357\u76fe\u7b26\u53f7","kip sign": "\u8001\u631d\u57fa\u666e\u7b26\u53f7","tugrik sign": "\u56fe\u683c\u91cc\u514b\u7b26\u53f7","drachma sign": "\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7","german penny symbol": "\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7","peso sign": "\u6bd4\u7d22\u7b26\u53f7","guarani sign": "\u74dc\u62c9\u5c3c\u7b26\u53f7","austral sign": "\u6fb3\u5143\u7b26\u53f7","hryvnia sign": "\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7","cedi sign": "\u585e\u5730\u7b26\u53f7","livre tournois sign": "\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7","spesmilo sign": "spesmilo\u7b26\u53f7","tenge sign": "\u575a\u6208\u7b26\u53f7","indian rupee sign": "\u5370\u5ea6\u5362\u6bd4","turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9","nordic mark sign": "\u5317\u6b27\u9a6c\u514b","manat sign": "\u9a6c\u7eb3\u7279\u7b26\u53f7","ruble sign": "\u5362\u5e03\u7b26\u53f7","yen character": "\u65e5\u5143\u5b57\u6837","yuan character": "\u4eba\u6c11\u5e01\u5143\u5b57\u6837","yuan character, in hong kong and taiwan":"\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09","yen/yuan character variant one":"\u5143\u5b57\u6837\uff08\u5927\u5199\uff09","Loading emoticons...": "\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...","Could not load emoticons":"\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7",People: "\u4eba\u7c7b","Animals and Nature": "\u52a8\u7269\u548c\u81ea\u7136","Food and Drink": "\u98df\u7269\u548c\u996e\u54c1",Activity: "\u6d3b\u52a8","Travel and Places": "\u65c5\u6e38\u548c\u5730\u70b9",Objects: "\u7269\u4ef6",Flags: "\u65d7\u5e1c",Characters: "\u5b57\u7b26","Characters (no spaces)": "\u5b57\u7b26(\u65e0\u7a7a\u683c)","{0} characters": "{0} \u4e2a\u5b57\u7b26","Error: Form submit field collision.":"\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002","Error: No form element found.":"\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002",Update: "\u66f4\u65b0","Color swatch": "\u989c\u8272\u6837\u672c",Turquoise: "\u9752\u7eff\u8272",Green: "\u7eff\u8272",Blue: "\u84dd\u8272",Purple: "\u7d2b\u8272","Navy Blue": "\u6d77\u519b\u84dd","Dark Turquoise": "\u6df1\u84dd\u7eff\u8272","Dark Green": "\u6df1\u7eff\u8272","Medium Blue": "\u4e2d\u84dd\u8272","Medium Purple": "\u4e2d\u7d2b\u8272","Midnight Blue": "\u6df1\u84dd\u8272",Yellow: "\u9ec4\u8272",Orange: "\u6a59\u8272",Red: "\u7ea2\u8272","Light Gray": "\u6d45\u7070\u8272",Gray: "\u7070\u8272","Dark Yellow": "\u6697\u9ec4\u8272","Dark Orange": "\u6df1\u6a59\u8272","Dark Red": "\u6df1\u7ea2\u8272","Medium Gray": "\u4e2d\u7070\u8272","Dark Gray": "\u6df1\u7070\u8272","Light Green": "\u6d45\u7eff\u8272","Light Yellow": "\u6d45\u9ec4\u8272","Light Red": "\u6d45\u7ea2\u8272","Light Purple": "\u6d45\u7d2b\u8272","Light Blue": "\u6d45\u84dd\u8272","Dark Purple": "\u6df1\u7d2b\u8272","Dark Blue": "\u6df1\u84dd\u8272",Black: "\u9ed1\u8272",White: "\u767d\u8272","Switch to or from fullscreen mode": "\u5207\u6362\u5168\u5c4f\u6a21\u5f0f","Open help dialog": "\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846",history: "\u5386\u53f2",styles: "\u6837\u5f0f",formatting: "\u683c\u5f0f\u5316",alignment: "\u5bf9\u9f50",indentation: "\u7f29\u8fdb",Font: "\u5b57\u4f53",Size: "\u5b57\u53f7","More...": "\u66f4\u591a...","Select...": "\u9009\u62e9...",Preferences: "\u9996\u9009\u9879",Yes: "\u662f",No: "\u5426","Keyboard Navigation": "\u952e\u76d8\u6307\u5f15",Version: "\u7248\u672c","Code view": "\u4ee3\u7801\u89c6\u56fe","Open popup menu for split buttons":"\u6253\u5f00\u5f39\u51fa\u5f0f\u83dc\u5355\uff0c\u7528\u4e8e\u62c6\u5206\u6309\u94ae","List Properties": "\u5217\u8868\u5c5e\u6027","List properties...": "\u6807\u9898\u5b57\u4f53\u5c5e\u6027","Start list at number": "\u4ee5\u6570\u5b57\u5f00\u59cb\u5217\u8868","Line height": "\u884c\u9ad8",comments: "\u5907\u6ce8","Format Painter": "\u683c\u5f0f\u5237","Insert/edit iframe": "\u63d2\u5165/\u7f16\u8f91\u6846\u67b6",Capitalization: "\u5927\u5199",lowercase: "\u5c0f\u5199",UPPERCASE: "\u5927\u5199","Title Case": "\u9996\u5b57\u6bcd\u5927\u5199","permanent pen": "\u8bb0\u53f7\u7b14","Permanent Pen Properties": "\u6c38\u4e45\u7b14\u5c5e\u6027","Permanent pen properties...": "\u6c38\u4e45\u7b14\u5c5e\u6027...","case change": "\u6848\u4f8b\u66f4\u6539","page embed": "\u9875\u9762\u5d4c\u5165","Advanced sort...": "\u9ad8\u7ea7\u6392\u5e8f...","Advanced Sort": "\u9ad8\u7ea7\u6392\u5e8f","Sort table by column ascending": "\u6309\u5217\u5347\u5e8f\u8868","Sort table by column descending": "\u6309\u5217\u964d\u5e8f\u8868",Sort: "\u6392\u5e8f",Order: "\u6392\u5e8f","Sort by": "\u6392\u5e8f\u65b9\u5f0f",Ascending: "\u5347\u5e8f",Descending: "\u964d\u5e8f","Column {0}": "\u5217{0}","Row {0}": "\u884c{0}","Spellcheck...": "\u62fc\u5199\u68c0\u67e5...","Misspelled word": "\u62fc\u5199\u9519\u8bef\u7684\u5355\u8bcd",Suggestions: "\u5efa\u8bae",Change: "\u66f4\u6539","Finding word suggestions": "\u67e5\u627e\u5355\u8bcd\u5efa\u8bae",Success: "\u6210\u529f",Repair: "\u4fee\u590d","Issue {0} of {1}": "\u5171\u8ba1{1}\u95ee\u9898{0}","Images must be marked as decorative or have an alternative text description":"\u56fe\u50cf\u5fc5\u987b\u6807\u8bb0\u4e3a\u88c5\u9970\u6027\u6216\u5177\u6709\u66ff\u4ee3\u6587\u672c\u63cf\u8ff0","Images must have an alternative text description. Decorative images are not allowed.":"\u56fe\u50cf\u5fc5\u987b\u5177\u6709\u66ff\u4ee3\u6587\u672c\u63cf\u8ff0\u3002\u4e0d\u5141\u8bb8\u4f7f\u7528\u88c5\u9970\u56fe\u50cf\u3002","Or provide alternative text:":"\u6216\u63d0\u4f9b\u5907\u9009\u6587\u672c\uff1a","Make image decorative:": "\u4f7f\u56fe\u50cf\u88c5\u9970\uff1a","ID attribute must be unique":"ID \u5c5e\u6027\u5fc5\u987b\u662f\u552f\u4e00\u7684","Make ID unique": "\u4f7f ID \u72ec\u4e00\u65e0\u4e8c","Keep this ID and remove all others":"\u4fdd\u7559\u6b64 ID \u5e76\u5220\u9664\u6240\u6709\u5176\u4ed6","Remove this ID": "\u5220\u9664\u6b64 ID","Remove all IDs": "\u6e05\u9664\u5168\u90e8IDs",Checklist: "\u6e05\u5355",Anchor: "\u951a\u70b9","Special character": "\u7279\u6b8a\u7b26\u53f7","Code sample": "\u4ee3\u7801\u793a\u4f8b",Color: "\u989c\u8272","Document properties": "\u6587\u6863\u5c5e\u6027","Image description": "\u56fe\u7247\u63cf\u8ff0",Image: "\u56fe\u7247","Insert link": "\u63d2\u5165\u94fe\u63a5",Target: "\u6253\u5f00\u65b9\u5f0f",Link: "\u94fe\u63a5",Poster: "\u5c01\u9762",Media: "\u5a92\u4f53",Print: "\u6253\u5370",Prev: "\u4e0a\u4e00\u4e2a","Find and replace": "\u67e5\u627e\u548c\u66ff\u6362","Whole words": "\u5168\u5b57\u5339\u914d","Insert template": "\u63d2\u5165\u6a21\u677f",
});
第四步(封装组件)
在src/components文件夹中封装Tinymce组件,文件目录如下:
plugins.js用来指定哪些插件被用在当前编辑器实例中:
// Any plugins you want to use has to be imported
// Deatil plugins list see https://www.tiny.cloud/docs/plugins/const plugins = [`advlist autolink lists link image charmap print preview anchor,searchreplace visualblocks code fullscreen,insertdatetime media table help wordcount image `
]export default plugins
toolbar.js用来配置工具栏上可用的按钮,多个控件使用空格分隔,使用“|”来创建分组:
// Here is a list of the toolbar
// Detail list see https://www.tiny.cloud/docs/general-configuration-guide/basic-setup/#toolbarconfigurationconst toolbars = ` | undo redo | cut copy | bold italic forecolor backcolor |alignleft aligncenter alignright alignjustify | formatselect | image | fullscreen preview | help `export default toolbars
index.vue文件完整内容如下:
<template><editorv-if="status === 'success'"v-model="myValue":init="init"></editor><!-- apiKey的使用方法 --><!-- <editor--><!-- v-model="myValue"--><!-- :init="init"--><!-- :api-key="apiKey"--><!-- >--><!-- </editor>--></template>
<script>
import Editor from "@tinymce/tinymce-vue"
import {uploadFile} from "@/request";
import config from "@/config";
import plugins from './plugins'
import toolbar from './toolbar'const defaultConfig = {width: 1000,height: 600,menubar: true,language: 'zh_CN'
}
export default {components: {Editor},props: {value: {type: String,default: "",},config: {type: Object,default: () => {return {width: 1000,height: 600,menubar: true,language: 'zh_CN'}}}},data() {return {myValue: this.value,apiKey: "在TinyMCE中申请的apiKey",//使用本地加载js的话可以不用apiKey'init: {plugins,toolbar,convert_urls: false,// 上传图片文件路径变为相对路径的解决方法removed_menuitems: 'media',width: Object.assign(defaultConfig, this.config).width,height: Object.assign(defaultConfig, this.config).height,menubar: Object.assign(defaultConfig, this.config).menubar,language: Object.assign(defaultConfig, this.config).language,language_url: "/tinymce/langs/zh_CN.js",// 汉化包resize: 'both',// 自定义图片上传images_upload_handler: async (blobInfo, success, failure) => {try {let formData = new FormData();formData.append("file", blobInfo.blob())formData.append("type", 1);let res = await uploadFile(formData);let url = `${config.downloadUrl}${res.url}`success(url)} catch (err) {console.log(err)}},},// tinymce组件scripttinyScript: null,status: 'pending'}},watch: {value(newValue) {this.myValue = newValue;},myValue(newValue) {this.$emit("input", newValue);},},created() {this.initTinyMceScript().then(() => {tinymce.init({})this.status = 'success'})},methods: {initTinyMceScript() {return new Promise(resolve => {if (this.tinyScript) {return resolve(null)}this.tinyScript = document.createElement("script");this.tinyScript.type = "text/javascript";this.tinyScript.src = "/tinymce/tinymce.min.js";document.body.appendChild(this.tinyScript);this.tinyScript.onload = () => {resolve(null)}})},desTinyMceScript() {if (this.tinyScript) {document.body.removeChild(this.tinyScript)this.tinyScript = null}}},beforeDestroy() {this.desTinyMceScript()}
}
</script>
封装的组件代码都在上面,然后简单讲下上面代码中踩过的坑及注意点:
1.动态引入JS文件
前面说过在项目中可能存在tinymce.min.js文件引入时机问题导致的报错,所以我们需要在组件内部动态引用js,代码如下,封装创建和销毁方法,在页面创建script标签并给属性赋值,然后监听加载完成,当加载完成后再去执行后续操作。
initTinyMceScript() {return new Promise(resolve => {if (this.tinyScript) {return resolve(null)}this.tinyScript = document.createElement("script");this.tinyScript.type = "text/javascript";this.tinyScript.src = "/tinymce/tinymce.min.js";document.body.appendChild(this.tinyScript);this.tinyScript.onload = () => {resolve(null)}})},desTinyMceScript() {if (this.tinyScript) {document.body.removeChild(this.tinyScript)this.tinyScript = null}}
要记得销毁噢:
beforeDestroy() {this.desTinyMceScript()}
2.自定义图片上传逻辑
有关图片上传的参数:
使用 images_upload_handler 可自定义上传处理逻辑。使用该配置,则无需使用其他上传配置选项,具体使用如下:
// 自定义图片上传images_upload_handler: async (blobInfo, success, failure) => {try {let formData = new FormData();formData.append("file", blobInfo.blob())formData.append("type", 1);let res = await uploadFile(formData);let url = `${config.downloadUrl}${res.url}`success(url)} catch (err) {console.log(err)}},
其中图片上传uploadFile()方法如下,这里就使用自己项目中封装的图片上传方法就OK:
/*** 上传文件* @param formData formData对象*/
const uploadFile = (formData: FormData) => request({url: cusConfig.uploadUrl,method: "POST",headers: {'Content-Type': 'multipart/form-data'},data: formData
})
如此就实现了图片的自定义上传。
3.上传图片文件路径变为相对路径
使用TinyMCE上传图片文件,接口返回相对根目录的地址,但是在TinyMCE编辑器源文件里路径变成了../../路径。
这很明显不是我们想要的,这样的路径后面是拿不到图片的,这里就需要配置convert_urls:false解决问题:
convert_urls: false,// 上传图片文件路径变为相对路径的解决方法
4.图片批量上传(非官方插件的使用)
首先去大佬的Tiny中文文档下载插件中文文档地址
将解压得到的文件夹,放到pubilc/tinymce目录下的plugins文件夹内:
并且创建index.js文件,内容如下:
// Exports the "axupimgs" plugin for usage with module loaders
// Usage:
// CommonJS:
// require('tinymce/plugins/axupimgs')
// ES2015:
// import 'tinymce/plugins/axupimgs'
require('./plugin.js');
接下来就去 toolbar.js和plugins.js中添加axupimgs:
此插件依赖image插件,不能单独使用,我们前面已经配置了图片的自定义上传,这里就不需要再做配置,功能如下:
总结
TinyMCE确实是一款易用、且功能强大的所见即所得的富文本编辑器,并且可扩展性非常强,如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以关注订阅一下:点击查看更多实用技巧及技术
相关文章:

Vue项目中集成TinyMCE富文本编辑器(图片批量上传等)
TinyMCE富文本在Vue中的使用 关于TinyMCE 实现效果 安装使用TinyMCE 第一步 第二步 1.官网申请Your Tiny API Key,并且配置访问域名: 2.使用css隐藏(这个就不讲了,不推荐使用) 3.全部由本地加载(推荐) 第三步(汉化包) 第四步(封装组…...

前端数据可视化之【title、legend、tooltip、toolbox 】配置项
目录 🌟Echarts配置项🌟Echarts配置项之 title组件🌟Echarts配置项之 legend组件🌟Echarts配置项之 tooltip组件🌟Echarts配置项之 toolbox组件🌟写在最后 🌟Echarts配置项 ECharts开源来自百度…...

microcom串口调试工具使用
microcom串口助手使用介绍 microcom是一个在终端中使用的串口助手,类似平常使用SSCOM一样的东西,不过是在终端中使用而已。 使用的是busybox构建的文件系统 microcom源码路径:busybox/miscutils/microcom.c microcom 参数: [r…...
深入了解Golang:基本语法与核心特性解析
1. 引言 Golang(Go)是谷歌开发的一门开源编程语言,于2007年首次公开亮相,随后在2012年正式发布。Golang以其简洁、高效和可靠的设计而备受开发者青睐。作为一门编译型语言,Golang具有静态类型和垃圾回收功能ÿ…...

短视频矩阵系统源码---php搭建
一、智能剪辑、矩阵分发、无人直播、爆款文案于一体独立应用开发 抖去推----主要针对本地生活的----移动端(小程序软件系统,目前是全国源头独立开发),开发功能大拆解分享,功能大拆解: (1)数据概览&#x…...
mysql 查询表字段名,注释 , 以及sql拼接查询出的内容
#sql查询字段名,注释操作拼接 #查询字段名和注释 select COLUMN_NAME,COLUMN_COMMENT from information_schema.COLUMNS where table_name 表名 and table_schema 库名 order by ordinal_position #查询整个内容 select * from information_schema.COLUMNS wh…...

【JavaEE】_Servlet API
目录 1. HttpServlet 1.1 init方法 1.2 destroy方法 1.3 service方法 1.4 Servlet的生命周期 1.5 代码示例 1.5.1 使用postman构造请求 1.5.2 使用ajax构造请求 2. HttpServletRequest 2.1 核心方法 2.2 代码示例1:打印请求信息 3. 前端给后端传参 3.1…...

macOS下matplotlib如何显示中文字体?
一般要显示中文会使用: plt.rcParams[font.sans-serif][SimHei] #用来正常显示中文标签 plt.rcParams[axes.unicode_minus]False #用来正常显示负号不过在macOS下通常会显示方块字: 解决方案: 把上面两句注释掉,更换为…...
7-Zip怎么设置字典大小 单词大小 固实数据大小,把大文件9.35G压缩成小1.56G
环境: Win10 专业版 7-Zip v23.01 问题描述: 7-Zip怎么设置字典大小 单词大小 固实数据大小,把大文件9.28G压缩成小1.56G 解决方案: 要在7-Zip中设置字典大小、单词大小和固实数据大小,可以按照以下步骤进行操作: 打开7-Zip文件管理器,并导航到你要压缩的文件所在的…...

使用CPR库和Python编写程序
以下是一个使用CPR库和Python编写的爬虫程序,用于爬取。此程序使用了proxy的代码。 import requests from cpr import CPR def get_proxy():url "https://www.duoip.cn/get_proxy"headers {"User-Agent": "Mozilla/5.0 (Windows NT …...
axios 请求的缓存封装
前言 咱们的网站或者程序,每一个页面和操作都需要请求后端接口来获取响应和渲染页面,抛开post请求方式的接口不说,部分get请求得到的数据,短时间内不会更新,或者短时间得到的响应数据不会变化,这个时候就可…...
Oracle性能调优实践中的几点心得
很多的时侯,做OracleDBA的我们,当应用管理员向我们通告现在应用很慢、数据库很慢的时侯,我们到数据库时做几个示例的Select也发现同样的问题时,有些时侯我们会无从下手,因为我们认为数据库的各种命种率都是满足Oracle文…...

勒索病毒最新变种.halo勒索病毒来袭,如何恢复受感染的数据?
引言: 在当今数字化时代,勒索病毒的威胁不断升级,其中.halo勒索病毒引起了广泛关注。本文91数据恢复将深入研究.halo勒索病毒的特点,探讨如何有效地恢复被其加密的数据文件,并分享预防这一威胁的关键措施。 .halo勒索…...
大厂秋招真题【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组
文章目录 【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组题目描述与示例题目描述输入描述输出描述示例输入输出说明 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 【前缀和】美团20230826秋招T5-平均数为k的最长连续子数组 题目描…...
bazel远程构建(Remote Execution) --- linux安装Redis
采用源码安装方式 下载地址:Download | Redis,下载最新稳定版本。 step1: 下载最新稳定版本 wget https://download.redis.io/redis-stable.tar.gz step2: 解压安装 tar -xzvf redis-stable.tar.gz cd redis-stable make 执行完 make 命令后&#…...
Maven在开发中的使用及理解
在JAVA项目中,我们通常需要对项目的构建和依赖进行管理,这个时候我们就需要MAVEN来对项目进行支持。 一.MAVEN构建 在整个MAVEN构建的过程中包含以下环节,也对应IDEA中MAVEN的对应功能。 清理Maven Clean 清理,则代表删除上一…...

2023/10/30-LED灯驱动开发
k1.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include "head.h" char kbuf[128] {}; unsigned int major; //定义三个指针指向映射后的虚拟内…...
华为OD 报文解压缩(100分)【java】B卷
华为OD统一考试A卷+B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入: 我用夸克网盘分享了「华为O…...

二、vue基础语法
一、模板语法 1、文本渲染 使用双花括号语法插入文本 <template><div><h3>msg: {{ message }}</h3></div> </template><script> export default {data() {return {message: "输出信息"}} } </script><style s…...

Java —— 程序逻辑控制
目录 1. 顺序结构 2. 分支结构 2.1 if 语句 2.1.1 语法格式1 2.1.2 语法格式2 2.1.3 语法格式3 2.2 switch 语句 3. 循环结构 3.1 while循环 3.2 break与continue 3.3 for循环 4. 输入输出 4.1 输出到控制台 格式化字符串 4.2 从键盘输入 5. 练习 和C语言类似地, Java的程序逻辑…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...