sa-item.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <template>
  2. <!-- 自定义slot -->
  3. <div class="c-item" :class="{br: br}" v-if="$slots.default && type != 'fast-btn'">
  4. <label class="c-label" v-if="name && name.length > 0">{{name}}:</label>
  5. <span v-else-if="name === undefined"></span>
  6. <label class="c-label" v-else></label>
  7. <span v-else></span>
  8. <slot></slot>
  9. </div>
  10. <!-- 普通input -->
  11. <div class="c-item" :class="{br: br}" v-else-if="type == 'text' || type == 'link'">
  12. <label class="c-label"><span v-if="need" style="color: red;">*</span>{{name}}:</label>
  13. <el-input type="text" :value="value" @input="onInput" :placeholder="placeholder?placeholder:name" :disabled="disabled"></el-input>
  14. </div>
  15. <!-- 数字input -->
  16. <div class="c-item" :class="{br: br}" v-else-if="type == 'num'">
  17. <label class="c-label"><span v-if="need" style="color: red;">*</span>{{name}}:</label>
  18. <el-input type="number" :value="value" @input="onInput" :placeholder="placeholder?placeholder:name" :disabled="disabled"></el-input>
  19. </div>
  20. <!-- 密码input -->
  21. <div class="c-item" :class="{br: br}" v-else-if="type == 'password'">
  22. <label class="c-label"><span v-if="need" style="color: red;">*</span>{{name}}:</label>
  23. <el-input type="password" :value="value" @input="onInput" :placeholder="placeholder?placeholder:name" :disabled="disabled"></el-input>
  24. </div>
  25. <!-- 多行文本域 -->
  26. <div class="c-item" :class="{br: br}" v-else-if="type == 'textarea'">
  27. <label class="c-label">{{name}}:</label>
  28. <div style="display: inline-block;">
  29. <el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" :value="value" @input="onInput" :placeholder="placeholder" :disabled="disabled"></el-input>
  30. </div>
  31. </div>
  32. <!-- 普通input - 列表 -->
  33. <div class="c-item" :class="{br: br}" v-else-if="type == 'text-list'">
  34. <label class="c-label">{{name}}:</label>
  35. <div class="c-item-mline">
  36. <div v-for="item in value_arr">
  37. <el-input v-model="item.value" @input="value_arr_change"></el-input>
  38. <el-link type="danger" class="del-rr" @click="value_arr_delete(item)">
  39. <i class="el-icon-close"></i>
  40. <small style="vertical-align: top;">删除</small>
  41. </el-link>
  42. </div>
  43. <el-link type="primary" @click="value_arr_push({value: ''})">[ + 添加 ]</el-link>
  44. <span class="c-remark" style="vertical-align: -5%;" v-if="remark">{{remark}}</span>
  45. </div>
  46. </div>
  47. <!-- 钱 money (单位 元) -->
  48. <div class="c-item" :class="{br: br}" v-else-if="type == 'money'">
  49. <label class="c-label">{{name}}:</label>
  50. <el-input type="text" :value="value" @input="onInput" :placeholder="placeholder" :disabled="disabled"></el-input>
  51. <span>元</span>
  52. </div>
  53. <!-- 钱 price-f (单位 分) -->
  54. <div class="c-item" :class="{br: br}" v-else-if="type == 'money-f'">
  55. <label class="c-label">{{name}}:</label>
  56. <el-input type="text" v-model="valueReal" @input="$emit('input', $event * 100)" :placeholder="placeholder" :disabled="disabled"></el-input>
  57. <span>元</span>
  58. </div>
  59. <!-- img -->
  60. <div class="c-item" :class="{br: br}" v-else-if="type == 'img'">
  61. <label class="c-label"><span v-if="need" style="color: red;">*</span>{{name}}:</label>
  62. <img :src="value" class="info-img" @click="sa.showImage(value, '400px', '400px')" v-if="!sa.isNull(value)">
  63. <slot name="tip"></slot>
  64. <el-link type="primary" @click="sa.uploadImage(src => {$emit('input', src); sa.ok2('上传成功');})">上传</el-link>
  65. </div>
  66. <!-- audio -->
  67. <div class="c-item" :class="{br: br}" v-else-if="type == 'audio'">
  68. <label class="c-label">{{name}}:</label>
  69. <el-link type="info" :href="value" target="_blank" v-if="!sa.isNull(value)">{{value}}</el-link>
  70. <el-link type="primary" @click="sa.uploadAudio(src => {$emit('input', src); sa.ok2('上传成功');})">上传</el-link>
  71. </div>
  72. <!-- video -->
  73. <div class="c-item" :class="{br: br}" v-else-if="type == 'video'">
  74. <label class="c-label">{{name}}:</label>
  75. <el-link type="info" :href="value" target="_blank" v-if="!sa.isNull(value)">{{value}}</el-link>
  76. <el-link type="primary" @click="sa.uploadVideo(src => {$emit('input', src); sa.ok2('上传成功');})">上传</el-link>
  77. </div>
  78. <!-- file -->
  79. <div class="c-item" :class="{br: br}" v-else-if="type == 'file'">
  80. <label class="c-label">{{name}}:</label>
  81. <el-link type="info" :href="value" target="_blank" v-if="!sa.isNull(value)">{{value}}</el-link>
  82. <el-link type="primary" @click="sa.uploadFile(src => {$emit('input', src); sa.ok2('上传成功');})">上传</el-link>
  83. </div>
  84. <!-- img-list -->
  85. <div class="c-item" :class="{br: br}" v-else-if="type == 'img-list'">
  86. <label class="c-label">{{name}}:</label>
  87. <div class="c-item-mline image-box">
  88. <div class="image-box-2" v-for="item in value_arr">
  89. <img :src="item.value" @click="sa.showImage(item.value, '500px', '400px')" />
  90. <p>
  91. <el-link @click="value_arr_delete(item)" style="color: #999;">
  92. <i class="el-icon-close" style="position: relative; top: 2px;"></i>
  93. 移除
  94. </el-link>
  95. </p>
  96. </div>
  97. <!-- 上传图集 -->
  98. <div class="image-box-2 up_img" @click="sa.uploadImageList(src => value_arr_push({value: src}))">
  99. <img src="../../static/img/up-icon.png">
  100. </div>
  101. </div>
  102. </div>
  103. <!-- audio-list、video-list、file-list、img-video-list -->
  104. <div class="c-item" :class="{br: br}" v-else-if="type == 'audio-list' || type == 'video-list' || type == 'file-list' || type == 'img-video-list'">
  105. <label class="c-label">{{name}}:</label>
  106. <div class="c-item-mline">
  107. <div v-for="item in value_arr">
  108. <el-link type="info" :href="item.value" target="_blank">{{item.value}}</el-link>
  109. <el-link type="danger" class="del-rr" @click="value_arr_delete(item)">
  110. <i class="el-icon-close"></i>
  111. <small style="vertical-align: top;">删除</small>
  112. </el-link>
  113. </div>
  114. <el-link type="primary" @click="sa.uploadAudioList(src => value_arr_push({value: src}))" v-if="type == 'audio-list'">上传</el-link>
  115. <el-link type="primary" @click="sa.uploadVideoList(src => value_arr_push({value: src}))" v-if="type == 'video-list'">上传</el-link>
  116. <el-link type="primary" @click="sa.uploadFileList(src => value_arr_push({value: src}))" v-if="type == 'file-list'">上传</el-link>
  117. <el-link type="primary" @click="sa.uploadImageList(src => value_arr_push({value: src}))" v-if="type == 'img-video-list'">上传图片</el-link>
  118. <el-link type="primary" @click="sa.uploadVideoList(src => value_arr_push({value: src}))" v-if="type == 'img-video-list'" style="margin-left: 7px;">上传视频</el-link>
  119. </div>
  120. </div>
  121. <!-- 富文本 richtext f -->
  122. <div class="c-item" style="margin-top: 10px;" :class="{br: br}" v-else-if="type == 'richtext' || type == 'f'">
  123. <label class="c-label">{{name}}:</label>
  124. <div class="editor-box c-item-mline">
  125. <div :id="'editor-' + editor_id"></div>
  126. </div>
  127. <div style="clear: both;"></div>
  128. </div>
  129. <!-- enum 枚举 -->
  130. <div class="c-item" :class="{br: br}" v-else-if="type == 'enum' || type == 'j' || type == 'switch'">
  131. <label class="c-label">{{name}}:</label>
  132. <el-radio-group v-if="jtype == 1 || jtype == 2" :class="{'s-radio-text': jtype == 2}" :value="value" @input="onInput">
  133. <el-radio label="" v-if="def">{{def}}</el-radio>
  134. <el-radio v-for="j in jvList" :key="j.key" :label="j.key">{{j.value}}</el-radio>
  135. </el-radio-group>
  136. <el-radio-group v-if="jtype == 3" :value="value" @input="onInput">
  137. <el-radio-button label="" v-if="def">{{def}}</el-radio-button>
  138. <el-radio-button v-for="j in jvList" :key="j.key" :label="j.key">{{j.value}}</el-radio-button>
  139. </el-radio-group>
  140. <el-select v-if="jtype == 4" :value="value" @input="onInput">
  141. <el-option label="" v-if="def" :value="def"></el-option>
  142. <el-option v-for="j in jvList" :key="j.key" :label="j.value" :value="j.key"></el-option>
  143. </el-select>
  144. </div>
  145. <!-- 日期选择器 -->
  146. <div class="c-item" :class="{br: br}" v-else-if="type == 'date'">
  147. <label class="c-label">{{name}}:</label>
  148. <el-date-picker type="date" value-format="yyyy-MM-dd" :value="value" @input="onInput" :placeholder="placeholder" :disabled="disabled"></el-date-picker>
  149. </div>
  150. <!-- 日期时间选择器 -->
  151. <div class="c-item" :class="{br: br}" v-else-if="type == 'datetime'">
  152. <label class="c-label"><span style="color: red;" v-if="need">*</span>{{name}}:</label>
  153. <el-date-picker type="datetime" value-format="yyyy-MM-dd HH:mm:ss" :value="value" @input="onInput" :placeholder="placeholder?placeholder:name" :disabled="disabled"></el-date-picker>
  154. </div>
  155. <!-- 时间选择器 -->
  156. <div class="c-item" :class="{br: br}" v-else-if="type == 'time'">
  157. <label class="c-label">{{name}}:</label>
  158. <el-time-picker value-format="HH:mm:ss" :value="value" @input="onInput" :placeholder="placeholder" :disabled="disabled"></el-time-picker>
  159. </div>
  160. <!-- 日期范围选择 -->
  161. <div class="c-item" :class="{br: br}" v-else-if="type == 'date-range'">
  162. <label class="c-label">{{name}}:</label>
  163. <el-date-picker
  164. type="daterange"
  165. range-separator="至"
  166. start-placeholder="开始日期"
  167. end-placeholder="结束日期"
  168. value-format="yyyy-MM-dd"
  169. :value="dateRangeValue"
  170. @input="dateRangeOnChange"
  171. :disabled="disabled"
  172. >
  173. </el-date-picker>
  174. </div>
  175. <!-- 滑块 -->
  176. <div class="c-item" :class="{br: br}" v-else-if="type == 'slider'">
  177. <label class="c-label">{{name}}:</label>
  178. <div style="display: inline-block; height: 0px; vertical-align: top; width: 250px;">
  179. <el-slider :value="value" @input="onInput" style="position: relative; top: -5px;" :disabled="disabled"></el-slider>
  180. </div>
  181. </div>
  182. <!-- 级联输入 -->
  183. <div class="c-item" :class="{br: br}" v-else-if="type == 'cascader'">
  184. <label class="c-label">{{name}}:</label>
  185. <el-cascader :value="value" @input="onInput" :options="options" :props="{expandTrigger: 'hover'}" :placeholder="placeholder" :disabled="disabled"></el-cascader>
  186. </div>
  187. <!-- 颜色输入 -->
  188. <div class="c-item" :class="{br: br}" style="height: 0px;" v-else-if="type == 'color'">
  189. <label class="c-label">{{name}}:</label>
  190. <el-color-picker :value="value" @input="onInput" :disabled="disabled"></el-color-picker>
  191. <span class="c-remark" style="vertical-align: top;">{{value}}</span>
  192. </div>
  193. <!-- 评分组件 -->
  194. <div class="c-item" :class="{br: br}" v-else-if="type == 'rate'">
  195. <label class="c-label">{{name}}:</label>
  196. <div style="display: inline-block;">
  197. <el-rate :value="value" @input="onInput" show-text :disabled="disabled"></el-rate>
  198. </div>
  199. </div>
  200. <!-- 快捷增删改查按钮 -->
  201. <div class="fast-btn" v-else-if="type == 'fast-btn'">
  202. <el-button type="primary" icon="el-icon-plus" @click="$parent.add()" v-if="showBtns.indexOf('add') != -1">新增</el-button>
  203. <el-button type="success" icon="el-icon-view" @click="$parent.getBySelect()" v-if="showBtns.indexOf('get') != -1">查看</el-button>
  204. <el-button type="danger" icon="el-icon-delete" @click="$parent.deleteByIds()" v-if="showBtns.indexOf('delete') != -1">删除</el-button>
  205. <el-button type="warning" icon="el-icon-download" @click="sa.exportExcel()" v-if="showBtns.indexOf('export') != -1">导出</el-button>
  206. <el-button type="info" icon="el-icon-refresh" @click="sa.f5()" v-if="showBtns.indexOf('reset') != -1">重置</el-button>
  207. <slot></slot>
  208. </div>
  209. <!-- 分页组件 -->
  210. <div class="page-box" v-else-if="type == 'page'">
  211. <el-pagination background
  212. layout="total, prev, pager, next,sizes,jumper"
  213. :current-page.sync="curr"
  214. :page-size.sync="size"
  215. :total="total"
  216. @current-change="changePage()"
  217. @size-change="changePage()">
  218. </el-pagination>
  219. </div>
  220. </template>
  221. <script>
  222. module.exports = {
  223. // props: ['name', 'value'],
  224. props: {
  225. // text、num、
  226. type: {
  227. default: 'text'
  228. },
  229. need:{
  230. type: Boolean,
  231. default:false
  232. },
  233. // label提示文字
  234. name: {
  235. type: String
  236. },
  237. // 绑定的值
  238. value: {},
  239. // 备注
  240. remark: '',
  241. // 提示文字
  242. placeholder: {},
  243. // 是否禁用
  244. disabled: {},
  245. // 是否换行
  246. br: {
  247. type: Boolean,
  248. default: false
  249. },
  250. // 日期范围时的选择字段,调用方需要加 .sync 修饰符
  251. start: {}, end: {},
  252. // type=menu时,值列表 -- 形如:{1: '正常[green]', 2: '禁用[red]'}
  253. jv: {default: ''},
  254. // type=menu时,具体的枚举类型 -- 1=单选框,2=单选文字,3=单选按钮,4=单选下拉框
  255. jtype: {default: 1},
  256. // type=menu时,增加的默认项文字
  257. def: {},
  258. // 级联选择的数据列表
  259. options: {},
  260. // 快捷按钮显示列表,形如:add,get,delete,export,reset
  261. show: {},
  262. // 分页信息
  263. curr: {}, size: {}, total: {}, sizes: {}
  264. },
  265. data() {
  266. return {
  267. // 日期范围时的值
  268. dateRangeValue: [],
  269. // 快捷按钮显示按钮列表
  270. showBtns: [],
  271. // type=menu时,解析的值列表 -- 形如:[{key: 1, value: '正常', color: 'green'}]
  272. jvList: [],
  273. // type = img-list 时,解析的元素List
  274. value_arr: [],
  275. // 富文本编辑器id
  276. editor_id: '',
  277. // 富文本编辑器对象
  278. editor: null,
  279. // money-f 的底层字段
  280. valueReal: ''
  281. }
  282. },
  283. watch: {
  284. // 监听一些类型的 value 变动
  285. value: function(oldValue, newValue) {
  286. // img-list、audio-list、video-list、file-list、img-video-list
  287. if(this.type == 'img-list' || this.type == 'audio-list' || this.type == 'video-list' || this.type == 'file-list'
  288. || this.type == 'img-video-list') {
  289. this.value_to_arr(this.value);
  290. }
  291. if(this.type == 'text-list' && this.value_arr.length == 0) {
  292. this.value_to_arr(this.value);
  293. }
  294. // 如果是富文本
  295. // if(this.type == 'richtext' || this.type == 'f') {
  296. // if(this.editor) {
  297. // // this.editor.txt.html(newValue);
  298. // $('#editor-' + this.editor_id + " .w-e-text").html(newValue);
  299. // }
  300. // }
  301. },
  302. },
  303. methods: {
  304. // input值发生变化时触发
  305. onInput: function($event) {
  306. this.$emit('input', $event);
  307. },
  308. // 日期范围选择时触发
  309. dateRangeOnChange: function(value) {
  310. console.log(value);
  311. this.dateRangeValue = value;
  312. this.start = value[0];
  313. this.end = value[1];
  314. this.$emit('update:start', value[0]);
  315. this.$emit('update:end', value[1]);
  316. },
  317. // 刷新分页
  318. changePage: function() {
  319. this.$emit('update:curr', this.curr);
  320. this.$emit('update:size', this.size);
  321. this.$emit('change');
  322. },
  323. // 解析枚举
  324. parseJv: function() {
  325. for(let key in this.jv) {
  326. let value = this.jv[key];
  327. let color = '';
  328. //
  329. if(value.indexOf('[') != -1 && value.endsWith(']')) {
  330. let index = value.indexOf('[');
  331. color = value.substring(index + 1, value.length - 1);
  332. value = value.substring(0, index);
  333. // console.log(color + ' --- ' + value);
  334. }
  335. //
  336. if(isNaN(key) == false) {
  337. key = parseInt(key);
  338. }
  339. //
  340. this.jvList.push({
  341. key: key,
  342. value: value,
  343. color: color
  344. })
  345. }
  346. },
  347. // 解析 value 为 value_arr
  348. value_to_arr: function(value) {
  349. let arr = sa.isNull(value) ? [] : value.split(',');
  350. let value_arr = [];
  351. for (var i = 0; i < arr.length; i++) {
  352. if(arr[i] != '' && arr[i].trim() != '') {
  353. value_arr.push({value: arr[i]});
  354. }
  355. }
  356. this.value_arr = value_arr;
  357. },
  358. // value_arr 数组增加值
  359. value_arr_push: function(item) {
  360. this.value_arr.push(item);
  361. // this.value = this.value_arr.join(',');
  362. this.$emit('input', sa.getArrayField(this.value_arr, 'value').join(','));
  363. },
  364. // value_arr 数组删除值
  365. value_arr_delete: function(item) {
  366. sa.arrayDelete(this.value_arr, item);
  367. // this.value = this.value_arr.join(',');
  368. this.$emit('input', sa.getArrayField(this.value_arr, 'value').join(','));
  369. },
  370. // value_arr 更改值时触发
  371. value_arr_change: function() {
  372. this.$emit('input', sa.getArrayField(this.value_arr, 'value').join(','));
  373. },
  374. // 创建富文本编辑器
  375. create_editor: function(content) {
  376. var E = window.wangEditor;
  377. var editor = new E('#editor-' + this.editor_id);
  378. editor.config.menus = [
  379. 'head', 'fontSize', 'fontName', 'italic', 'underline', 'strikeThrough', 'foreColor', 'backColor', 'link', 'list',
  380. 'justify', 'quote', 'emoticon', 'image', 'table', 'code', 'undo', 'redo' // 重复
  381. ]
  382. editor.config.debug = true; // debug模式
  383. // editor.config.uploadFileName = 'file'; // 图片流name
  384. editor.config.withCredentials = true; // 跨域携带cookie
  385. editor.config.uploadImgMaxSize = 100 * 1024 * 1024; // 图片大小最大100M
  386. // editor.config.uploadImgShowBase64 = true // 使用 base64 保存图片
  387. // 监听内容变动
  388. editor.config.onchange = function (newHtml) {
  389. // console.log("change 之后最新的 html", newHtml);
  390. this.$emit('input', newHtml);
  391. }.bind(this);
  392. // 重写上传图片的函数到OSS
  393. editor.config.customUploadImg = function(files, insert) {
  394. var file = files[0]; // 文件对象
  395. startUploadImage2(file, function(src) {
  396. insert(src);
  397. sa.msg('上传成功');
  398. });
  399. }
  400. editor.create(); // 创建
  401. editor.txt.html(content); // 为编辑器赋值
  402. this.editor = editor;
  403. // setTimeout(function() {
  404. // $('.editor-box').height($('.editor-box').height());
  405. // })
  406. },
  407. // 为编辑器赋值
  408. editorSet: function(value) {
  409. this.editor.txt.html(value);
  410. },
  411. valueSet(valueReal) {
  412. this.valueReal = valueReal;
  413. }
  414. },
  415. created() {
  416. // console.log(this.br);
  417. if(this.type == 'fast-btn') {
  418. this.showBtns = this.show.split(',');
  419. for (var i = 0; i < this.showBtns.length; i++) {
  420. this.showBtns[i] = this.showBtns[i].trim();
  421. }
  422. }
  423. // 如果是枚举
  424. if(this.type == 'enum' || this.type == 'j' || this.type == 'switch') {
  425. this.parseJv();
  426. }
  427. // 如果是 img-list 等
  428. if(this.type == 'img-list' || this.type == 'audio-list' || this.type == 'video-list' || this.type == 'file-list'
  429. || this.type == 'img-video-list' || this.type == 'text-list') {
  430. this.value_to_arr(this.value);
  431. }
  432. // 如果是富文本
  433. if(this.type == 'richtext' || this.type == 'f') {
  434. this.editor_id = sa.randomString(32);
  435. this.$nextTick(function() {
  436. this.create_editor(this.value);
  437. })
  438. }
  439. // 如果是 money-f
  440. if(this.type == 'money-f') {
  441. if(this.value) {
  442. this.valueReal = this.value / 100;
  443. }
  444. }
  445. }
  446. }
  447. </script>
  448. <style scoped>
  449. </style>