Merge branch 'master' of github.com:kuaifan/dootask into develop
# Conflicts: # app/Http/Controllers/Api/DialogController.php # electron/package.json # package.json # public/css/app.css # public/js/app.js # public/js/build/146.js # public/js/build/146.js.LICENSE.txt # public/js/build/178.js # public/js/build/178.js.LICENSE.txt # public/js/build/199.js # public/js/build/199.js.LICENSE.txt # public/js/build/309.js # public/js/build/328.js.LICENSE.txt # public/js/build/388.js # public/js/build/43.js # public/js/build/46.js.LICENSE.txt # public/js/build/857.js # public/js/build/857.js.LICENSE.txt # public/js/build/893.js
This commit is contained in:
379
resources/assets/js/components/AceEditor.vue
Normal file
379
resources/assets/js/components/AceEditor.vue
Normal file
@@ -0,0 +1,379 @@
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: 'AceEditor',
|
||||
props: {
|
||||
value: {
|
||||
default: ''
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
default: 'auto'
|
||||
},
|
||||
ext: {
|
||||
type: String,
|
||||
default: 'txt'
|
||||
},
|
||||
height: {
|
||||
type: Number || null,
|
||||
default: null
|
||||
},
|
||||
width: {
|
||||
type: Number || null,
|
||||
default: null
|
||||
},
|
||||
wrap: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('div', {
|
||||
class: "no-dark-mode"
|
||||
})
|
||||
},
|
||||
data: () => ({
|
||||
code: '',
|
||||
editor: null,
|
||||
cursorPosition: {
|
||||
row: 0,
|
||||
column: 0
|
||||
},
|
||||
supportedModes: {
|
||||
"Apache_Conf": [
|
||||
"^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"
|
||||
],
|
||||
"BatchFile": [
|
||||
"bat|cmd"
|
||||
],
|
||||
"C_Cpp": [
|
||||
"cpp|c|cc|cxx|h|hh|hpp|ino"
|
||||
],
|
||||
"CSharp": [
|
||||
"cs"
|
||||
],
|
||||
"CSS": [
|
||||
"css"
|
||||
],
|
||||
"Dockerfile": [
|
||||
"^Dockerfile"
|
||||
],
|
||||
"golang": [
|
||||
"go"
|
||||
],
|
||||
"HTML": [
|
||||
"html|htm|xhtml|vue|we|wpy"
|
||||
],
|
||||
"Java": [
|
||||
"java"
|
||||
],
|
||||
"JavaScript": [
|
||||
"js|jsm|jsx"
|
||||
],
|
||||
"JSON": [
|
||||
"json"
|
||||
],
|
||||
"JSP": [
|
||||
"jsp"
|
||||
],
|
||||
"LESS": [
|
||||
"less"
|
||||
],
|
||||
"Lua": [
|
||||
"lua"
|
||||
],
|
||||
"Makefile": [
|
||||
"^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"
|
||||
],
|
||||
"Markdown": [
|
||||
"md|markdown"
|
||||
],
|
||||
"MySQL": [
|
||||
"mysql"
|
||||
],
|
||||
"Nginx": [
|
||||
"nginx|conf"
|
||||
],
|
||||
"INI": [
|
||||
"ini|conf|cfg|prefs"
|
||||
],
|
||||
"ObjectiveC": [
|
||||
"m|mm"
|
||||
],
|
||||
"Perl": [
|
||||
"pl|pm"
|
||||
],
|
||||
"Perl6": [
|
||||
"p6|pl6|pm6"
|
||||
],
|
||||
"pgSQL": [
|
||||
"pgsql"
|
||||
],
|
||||
"PHP_Laravel_blade": [
|
||||
"blade.php"
|
||||
],
|
||||
"PHP": [
|
||||
"php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"
|
||||
],
|
||||
"Powershell": [
|
||||
"ps1"
|
||||
],
|
||||
"Python": [
|
||||
"py"
|
||||
],
|
||||
"R": [
|
||||
"r"
|
||||
],
|
||||
"Ruby": [
|
||||
"rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"
|
||||
],
|
||||
"Rust": [
|
||||
"rs"
|
||||
],
|
||||
"SASS": [
|
||||
"sass"
|
||||
],
|
||||
"SCSS": [
|
||||
"scss"
|
||||
],
|
||||
"SH": [
|
||||
"sh|bash|^.bashrc"
|
||||
],
|
||||
"SQL": [
|
||||
"sql"
|
||||
],
|
||||
"SQLServer": [
|
||||
"sqlserver"
|
||||
],
|
||||
"Swift": [
|
||||
"swift"
|
||||
],
|
||||
"Text": [
|
||||
"txt"
|
||||
],
|
||||
"Typescript": [
|
||||
"ts|typescript|str"
|
||||
],
|
||||
"VBScript": [
|
||||
"vbs|vb"
|
||||
],
|
||||
"Verilog": [
|
||||
"v|vh|sv|svh"
|
||||
],
|
||||
"XML": [
|
||||
"xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"
|
||||
],
|
||||
"YAML": [
|
||||
"yaml|yml"
|
||||
],
|
||||
"Compress": [
|
||||
"tar|zip|7z|rar|gz|arj|z"
|
||||
],
|
||||
"images": [
|
||||
"icon|jpg|jpeg|png|bmp|gif|tif|emf"
|
||||
]
|
||||
},
|
||||
}),
|
||||
mounted() {
|
||||
$A.loadScriptS([
|
||||
'js/ace/ace.js',
|
||||
'js/ace/mode-json.js',
|
||||
], () => {
|
||||
// set init editor size
|
||||
this.setSize(this.$el, {height: this.height, width: this.width})
|
||||
|
||||
// init ace editor
|
||||
this.editor = window.ace.edit(this.$el, {
|
||||
wrap: this.wrap,
|
||||
showPrintMargin: false,
|
||||
readOnly: this.readOnly,
|
||||
keyboardHandler: 'vscode',
|
||||
})
|
||||
this.editor.session.setMode(`ace/mode/${this.getFileMode()}`)
|
||||
|
||||
// emit 'mounted' event
|
||||
this.$emit('mounted', this.editor)
|
||||
|
||||
// official syntax validation workers include 'coffee', 'css', 'html'
|
||||
// 'javascript', 'json', 'lua', 'php', 'xml' and 'xquery'
|
||||
if (this.editor.session.$worker) {
|
||||
this.editor.session.$worker.addEventListener('annotate', this.workerMessage, false)
|
||||
}
|
||||
|
||||
// set value and clear selection
|
||||
this.editor.setValue(this.value)
|
||||
this.editor.clearSelection()
|
||||
|
||||
// set ace editor options and theme
|
||||
this.editor.setOptions(this.options)
|
||||
this.editTheme && this.editor.setTheme(`ace/theme/${this.editTheme}`)
|
||||
|
||||
// 设置快捷键
|
||||
this.editor.commands.addCommand({
|
||||
name: '保存文件',
|
||||
bindKey: {
|
||||
win: 'Ctrl-S',
|
||||
mac: 'Command-S'
|
||||
},
|
||||
exec: () => {
|
||||
this.$emit("saveData")
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
|
||||
// 触发修改内容
|
||||
this.editor.getSession().on('change', () => {
|
||||
this.code = this.editor.getValue()
|
||||
this.$emit('input', this.code);
|
||||
});
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* listening lint events from worker
|
||||
* @param data
|
||||
*/
|
||||
workerMessage({data}) {
|
||||
// record current cursor position
|
||||
this.cursorPosition = this.editor.selection.getCursor()
|
||||
const [validationInfo] = data
|
||||
if (validationInfo && validationInfo.type === 'error') {
|
||||
this.$emit('validationFailed', validationInfo)
|
||||
} else {
|
||||
this.$emit('change', this.editor.getValue())
|
||||
}
|
||||
},
|
||||
/**
|
||||
* set editor size
|
||||
* @param dom
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
setSize(dom, {width = this.width, height = this.height}) {
|
||||
dom.style.width = width && typeof width === 'number' ? `${width}px` : '100%'
|
||||
dom.style.height = height && typeof height === 'number' ? `${height}px` : '100%'
|
||||
this.$nextTick(() => this.editor && this.editor.resize())
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取文件类型
|
||||
* @returns {string}
|
||||
*/
|
||||
getFileMode() {
|
||||
var ext = this.ext || "text";
|
||||
for (var name in this.supportedModes) {
|
||||
var data = this.supportedModes[name],
|
||||
suffixs = data[0].split('|'),
|
||||
mode = name.toLowerCase();
|
||||
for (var i = 0; i < suffixs.length; i++) {
|
||||
if (ext == suffixs[i]) {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'text';
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['themeIsDark']),
|
||||
|
||||
editTheme() {
|
||||
if (this.theme == 'auto') {
|
||||
if (this.themeIsDark) {
|
||||
return "dracula-dark"
|
||||
} else {
|
||||
return "chrome"
|
||||
}
|
||||
}
|
||||
return this.theme
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/**
|
||||
* watching and set options
|
||||
* @param newOptions ace editor options
|
||||
*/
|
||||
options(newOptions) {
|
||||
if (newOptions && typeof newOptions === 'object') {
|
||||
this.editor && this.editor.setOptions(newOptions)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* watching and set theme
|
||||
* @param newTheme
|
||||
*/
|
||||
editTheme(newTheme) {
|
||||
if (newTheme && typeof newTheme === 'string') {
|
||||
this.editor && this.editor.setTheme(`ace/theme/${newTheme}`)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* watching and set ext
|
||||
* @param newExt
|
||||
*/
|
||||
ext(newExt) {
|
||||
if (newExt && typeof newExt === 'string') {
|
||||
this.editor && this.editor.session.setMode(`ace/mode/${this.getFileMode()}`)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* watching and set width
|
||||
* @param newWidth
|
||||
*/
|
||||
width(newWidth) {
|
||||
this.setSize(this.el, {width: newWidth})
|
||||
},
|
||||
/**
|
||||
* watching and set height
|
||||
* @param newHeight
|
||||
*/
|
||||
height(newHeight) {
|
||||
this.setSize(this.el, {height: newHeight})
|
||||
},
|
||||
/**
|
||||
* watching and set readOnly
|
||||
* @param only
|
||||
*/
|
||||
readOnly(only) {
|
||||
if (typeof only === 'boolean') {
|
||||
this.editor && this.editor.setReadOnly(only)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* watching and set code
|
||||
* @param newCode
|
||||
*/
|
||||
value(newCode) {
|
||||
if (!this.editor) {
|
||||
return
|
||||
}
|
||||
if (newCode == this.code) {
|
||||
return;
|
||||
}
|
||||
this.editor.setValue(newCode)
|
||||
this.editor.clearSelection()
|
||||
const {row, column} = this.cursorPosition
|
||||
// move cursor to current position
|
||||
this.editor.selection.moveCursorTo(row, column)
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.editor) {
|
||||
if (this.editor.session.$worker) {
|
||||
this.editor.session.$worker.removeEventListener('message', this.workerMessage, false)
|
||||
}
|
||||
this.editor.destroy()
|
||||
this.editor.container.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,318 +0,0 @@
|
||||
<template>
|
||||
<div :id="id" class="luckysheet-component">
|
||||
<Loading v-if="loadIng" class="luckysheet-loading"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.luckysheet-component {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
.luckysheet-loading {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import XLSX from "xlsx";
|
||||
|
||||
export default {
|
||||
name: 'LuckySheet',
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return "luckysheet_" + Math.round(Math.random() * 10000);
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: [Object, Array],
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loadIng: true,
|
||||
sheetLoaded: false,
|
||||
|
||||
bakValue: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
$A.loadScriptS([
|
||||
'js/luckysheet/plugins/css/pluginsCss.css',
|
||||
'js/luckysheet/plugins/plugins.css',
|
||||
'js/luckysheet/css/luckysheet.css',
|
||||
'js/luckysheet/assets/iconfont/iconfont.css',
|
||||
//
|
||||
'js/luckysheet/plugins/js/plugin.js',
|
||||
'js/luckysheet/luckysheet.umd.js',
|
||||
], () => {
|
||||
this.loadIng = false;
|
||||
this.bakValue = JSON.stringify(this.value);
|
||||
this.loadSheet(this.value);
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(value) {
|
||||
if (this.bakValue == JSON.stringify(value)) {
|
||||
return;
|
||||
}
|
||||
this.bakValue = JSON.stringify(value);
|
||||
this.loadSheet(value);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadSheet(value) {
|
||||
let lang = 'zh';
|
||||
switch (this.getLanguage()) {
|
||||
case 'CN':
|
||||
case 'TC':
|
||||
lang = 'zh';
|
||||
break;
|
||||
default:
|
||||
lang = 'en';
|
||||
break;
|
||||
}
|
||||
//
|
||||
this.sheetLoaded && window.luckysheet.destroy();
|
||||
this.sheetLoaded = true;
|
||||
let config = {
|
||||
container: this.id,
|
||||
showinfobar: false,
|
||||
plugins: [
|
||||
'chart'
|
||||
],
|
||||
showtoolbarConfig: {
|
||||
chart: false
|
||||
},
|
||||
cellRightClickConfig: {
|
||||
chart: false
|
||||
},
|
||||
lang: lang,
|
||||
loading: {
|
||||
image: 'image://' + $A.originUrl('js/luckysheet/css/loading.gif')
|
||||
},
|
||||
data: $A.isArray(value) ? $A.cloneJSON(value) : [
|
||||
{
|
||||
"name": "Sheet1",
|
||||
}
|
||||
],
|
||||
hook:{
|
||||
updated: () => {
|
||||
this.updateData();
|
||||
},
|
||||
sheetActivate: () => {
|
||||
this.$nextTick(this.updateData);
|
||||
}
|
||||
},
|
||||
};
|
||||
if (this.readOnly) {
|
||||
config.showtoolbar = false;
|
||||
config.allowEdit = false;
|
||||
config.enableAddRow = false;
|
||||
config.enableAddBackTop = false;
|
||||
config.showsheetbarConfig = {
|
||||
add: false
|
||||
};
|
||||
config.sheetRightClickConfig = {
|
||||
delete: false, // 删除
|
||||
copy: false, // 复制
|
||||
rename: false, //重命名
|
||||
color: false, //更改颜色
|
||||
hide: false, //隐藏,取消隐藏
|
||||
move: false, //向左移,向右移
|
||||
};
|
||||
}
|
||||
window.luckysheet.create(config);
|
||||
},
|
||||
|
||||
updateData() {
|
||||
const value = window.luckysheet.getAllSheets();
|
||||
value.forEach((item) => {
|
||||
delete item.ch_width;
|
||||
delete item.rh_height;
|
||||
delete item.index;
|
||||
});
|
||||
this.bakValue = JSON.stringify(value);
|
||||
this.$emit('input', value);
|
||||
},
|
||||
|
||||
chatatABC(n) {
|
||||
var orda = 'a'.charCodeAt(0);
|
||||
var ordz = 'z'.charCodeAt(0);
|
||||
var len = ordz - orda + 1;
|
||||
var s = "";
|
||||
while (n >= 0) {
|
||||
s = String.fromCharCode(n % len + orda) + s;
|
||||
n = Math.floor(n / len) - 1;
|
||||
}
|
||||
return s.toUpperCase();
|
||||
},
|
||||
|
||||
exportExcel(bookName, bookType) {
|
||||
let allSheetData = window.luckysheet.getluckysheetfile();
|
||||
let SheetNames = [];
|
||||
let Sheets = {};
|
||||
allSheetData.forEach((sheetData) => {
|
||||
let downOriginData = sheetData.data;
|
||||
let arr = []; // 所有的单元格数据组成的二维数组
|
||||
let bgConfig = {};
|
||||
let cellValue = null;
|
||||
// 获取单元格的背景色
|
||||
let setBackground = (row, col, bg) => {
|
||||
var colA = this.chatatABC(col);
|
||||
var key = colA + (row + 1);
|
||||
bgConfig[key] = bg.replace(/\#?/, '');
|
||||
}
|
||||
// 获取二维数组
|
||||
for (let row = 0; row < downOriginData.length; row++) {
|
||||
let arrRow = [];
|
||||
for (let col = 0; col < downOriginData[row].length; col++) {
|
||||
cellValue = downOriginData[row][col]
|
||||
if (cellValue) {
|
||||
// 处理单元格的背景颜色
|
||||
if (cellValue.bg) {
|
||||
setBackground(row, col, cellValue.bg)
|
||||
}
|
||||
if (cellValue.ct != null && cellValue.ct.t == 'd') {
|
||||
// d为时间格式 2019-01-01 或者2019-01-01 10:10:10
|
||||
arrRow.push(new Date(cellValue.m.replace(/\-/g, '/'))) //兼容IE
|
||||
} else if (cellValue.m && this.isPercentage(cellValue)) {
|
||||
//百分比问题
|
||||
arrRow.push(cellValue.m)
|
||||
} else {
|
||||
arrRow.push(cellValue.v)
|
||||
}
|
||||
}
|
||||
}
|
||||
arr.push(arrRow)
|
||||
}
|
||||
let opts = {
|
||||
dateNF: 'm/d/yy h:mm',
|
||||
cellDates: true,
|
||||
cellStyles: true
|
||||
}
|
||||
let ws = XLSX.utils.aoa_to_sheet(arr, opts)
|
||||
//
|
||||
let reg = /[\u4e00-\u9fa5]/g;
|
||||
for (let key in ws) {
|
||||
if (!ws.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
let item = ws[key]
|
||||
if (item.t === 'd') {
|
||||
if (item.w) {
|
||||
//时间格式的设置
|
||||
let arr = item.w.split(' ')
|
||||
if (arr[1] && arr[1] == '0:00') {
|
||||
ws[key].z = 'm/d/yy'
|
||||
} else {
|
||||
item.z = 'yyyy/m/d h:mm:ss'
|
||||
}
|
||||
}
|
||||
} else if (item.t === 's') {
|
||||
//百分比设置格式
|
||||
if (item.v && !item.v.match(reg) && item.v.indexOf('%') > -1) {
|
||||
item.t = 'n'
|
||||
item.z = '0.00%'
|
||||
item.v = Number.parseFloat(item.v) / 100
|
||||
} else if (item.v && item.v.match(reg)) {
|
||||
//含有中文的设置居中样式
|
||||
item['s'] = {
|
||||
alignment: {vertical: 'center', horizontal: 'center'}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置单元格样式
|
||||
if (bgConfig[key]) {
|
||||
ws[key]['s'] = {
|
||||
alignment: {vertical: 'center', horizontal: 'center'},
|
||||
fill: {bgColor: {indexed: 32}, fgColor: {rgb: bgConfig[key]}},
|
||||
border: {
|
||||
top: {style: 'thin', color: {rgb: '999999'}},
|
||||
bottom: {style: 'thin', color: {rgb: '999999'}},
|
||||
left: {style: 'thin', color: {rgb: '999999'}},
|
||||
right: {style: 'thin', color: {rgb: '999999'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 内容
|
||||
SheetNames.push(sheetData.name)
|
||||
Sheets[sheetData.name] = Object.assign({}, ws);
|
||||
// 合并单元格配置
|
||||
let mergeConfig = sheetData.config.merge
|
||||
let mergeArr = [];
|
||||
if (JSON.stringify(mergeConfig) !== '{}') {
|
||||
mergeArr = this.handleMergeData(mergeConfig)
|
||||
Sheets[sheetData.name]['!merges'] = mergeArr
|
||||
}
|
||||
});
|
||||
//
|
||||
const data = {
|
||||
SheetNames: SheetNames,
|
||||
Sheets: Sheets
|
||||
}
|
||||
const opts = {
|
||||
bookType: bookType || "xlsx"
|
||||
}
|
||||
const filename = bookName + "." + (bookType == 'xlml' ? 'xls' : bookType);
|
||||
if (this.$Electron) {
|
||||
this.$Electron.ipcRenderer.send('saveSheet', data, filename, opts);
|
||||
} else {
|
||||
XLSX.writeFile(data, filename, opts);
|
||||
}
|
||||
},
|
||||
|
||||
isPercentage(value) {
|
||||
return /%$/.test(value.m) && value.ct && value.ct.t === 'n'
|
||||
},
|
||||
|
||||
handleMergeData(origin) {
|
||||
let result = []
|
||||
if (origin instanceof Object) {
|
||||
var r = "r",
|
||||
c = "c",
|
||||
cs = "cs",
|
||||
rs = "rs";
|
||||
for (var key in origin) {
|
||||
if (!origin.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
var startR = origin[key][r];
|
||||
var endR = origin[key][r];
|
||||
var startC = origin[key][c];
|
||||
var endC = origin[key][c];
|
||||
|
||||
// 如果只占一行 为1 如果占两行 为2
|
||||
if (origin[key][cs] > 0) {
|
||||
endC = startC + (origin[key][cs] - 1);
|
||||
}
|
||||
if (origin[key][rs] > 0) {
|
||||
endR = startR + (origin[key][rs] - 1);
|
||||
}
|
||||
// s为合并单元格的开始坐标 e为结束坐标
|
||||
var obj = {s: {"r": startR, "c": startC}, e: {"r": endR, "c": endC}}
|
||||
result.push(obj)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
17
resources/assets/js/functions/web.js
vendored
17
resources/assets/js/functions/web.js
vendored
@@ -355,6 +355,23 @@
|
||||
*/
|
||||
dialogCompleted(dialog) {
|
||||
return this.dialogTags(dialog).find(({color}) => color == 'success');
|
||||
},
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param url
|
||||
*/
|
||||
downFile(url) {
|
||||
if (!url) {
|
||||
return
|
||||
}
|
||||
if ($A.Electron) {
|
||||
$A.Electron.shell.openExternal(url).catch(() => {
|
||||
$A.modalError("下载失败");
|
||||
});
|
||||
} else {
|
||||
window.open(url)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div v-else-if="msgData.type === 'loading'" class="dialog-content loading"><Loading/></div>
|
||||
<!--文件-->
|
||||
<div v-else-if="msgData.type === 'file'" :class="['dialog-content', msgData.msg.type]">
|
||||
<a :href="msgData.msg.path" target="_blank">
|
||||
<div class="dialog-file" @click="downFile">
|
||||
<img v-if="msgData.msg.type === 'img'" class="file-img" :style="imageStyle(msgData.msg)" :src="msgData.msg.thumb"/>
|
||||
<div v-else class="file-box">
|
||||
<img class="file-thumb" :src="msgData.msg.thumb"/>
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="file-size">{{$A.bytesToSize(msgData.msg.size)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!--未知-->
|
||||
<div v-else class="dialog-content unknown">{{$L("未知的消息类型")}}</div>
|
||||
@@ -56,6 +56,7 @@
|
||||
|
||||
<script>
|
||||
import WCircle from "../../../components/WCircle";
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "DialogView",
|
||||
@@ -84,6 +85,8 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['userToken']),
|
||||
|
||||
readList() {
|
||||
return this.read_list.filter(({read_at}) => read_at)
|
||||
},
|
||||
@@ -162,6 +165,17 @@ export default {
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
downFile() {
|
||||
$A.modalConfirm({
|
||||
title: '下载文件',
|
||||
content: `${this.msgData.msg.name} (${$A.bytesToSize(this.msgData.msg.size)})`,
|
||||
okText: '立即下载',
|
||||
onOk: () => {
|
||||
$A.downFile($A.apiUrl(`dialog/msg/download?msg_id=${this.msgData.id}&token=${this.userToken}`))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,8 +341,21 @@ export default {
|
||||
const postFiles = Array.prototype.slice.call(files);
|
||||
if (postFiles.length > 0) {
|
||||
e.preventDefault();
|
||||
postFiles.forEach((file) => {
|
||||
this.$refs.chatUpload.upload(file);
|
||||
this.pasteFile = [];
|
||||
this.pasteItem = [];
|
||||
postFiles.some(file => {
|
||||
let reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = ({target}) => {
|
||||
this.pasteFile.push(file)
|
||||
this.pasteItem.push({
|
||||
type: $A.getMiddle(file.type, null, '/'),
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
result: target.result
|
||||
})
|
||||
this.pasteShow = true
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -33,18 +33,12 @@
|
||||
<div v-if="file.type=='mind'" class="header-hint">
|
||||
{{$L('选中节点,按enter键添加同级节点,tab键添加子节点')}}
|
||||
</div>
|
||||
<Dropdown v-if="file.type=='mind' || file.type=='flow' || file.type=='sheet'"
|
||||
<Dropdown v-if="file.type=='mind' || file.type=='flow'"
|
||||
trigger="click"
|
||||
class="header-hint"
|
||||
@on-click="exportMenu">
|
||||
<a href="javascript:void(0)">{{$L('导出')}}<Icon type="ios-arrow-down"></Icon></a>
|
||||
<DropdownMenu v-if="file.type=='sheet'" slot="list">
|
||||
<DropdownItem name="xlsx">{{$L('导出XLSX')}}</DropdownItem>
|
||||
<DropdownItem name="xlml">{{$L('导出XLS')}}</DropdownItem>
|
||||
<DropdownItem name="csv">{{$L('导出CSV')}}</DropdownItem>
|
||||
<DropdownItem name="txt">{{$L('导出TXT')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu v-else slot="list">
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem name="png">{{$L('导出PNG图片')}}</DropdownItem>
|
||||
<DropdownItem name="pdf">{{$L('导出PDF文件')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
@@ -58,8 +52,8 @@
|
||||
</template>
|
||||
<Flow v-else-if="file.type=='flow'" ref="myFlow" v-model="contentDetail" @saveData="handleClick('saveBefore')"/>
|
||||
<Minder v-else-if="file.type=='mind'" ref="myMind" v-model="contentDetail" @saveData="handleClick('saveBefore')"/>
|
||||
<LuckySheet v-else-if="file.type=='sheet'" ref="mySheet" v-model="contentDetail"/>
|
||||
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail"/>
|
||||
<AceEditor v-else-if="['code', 'txt'].includes(file.type)" v-model="contentDetail.content" :ext="file.ext" @saveData="handleClick('saveBefore')"/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="contentLoad" class="content-load"><Loading/></div>
|
||||
@@ -74,13 +68,13 @@ Vue.use(Minder)
|
||||
|
||||
const MDEditor = () => import('../../../components/MDEditor/index');
|
||||
const TEditor = () => import('../../../components/TEditor');
|
||||
const LuckySheet = () => import('../../../components/LuckySheet');
|
||||
const Flow = () => import('../../../components/Flow');
|
||||
const AceEditor = () => import('../../../components/AceEditor');
|
||||
const OnlyOffice = () => import('../../../components/OnlyOffice');
|
||||
|
||||
export default {
|
||||
name: "FileContent",
|
||||
components: {TEditor, MDEditor, LuckySheet, Flow, OnlyOffice},
|
||||
components: {AceEditor, TEditor, MDEditor, Flow, OnlyOffice},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
@@ -227,10 +221,12 @@ export default {
|
||||
getContent() {
|
||||
if (!this.fileId) {
|
||||
this.contentDetail = {};
|
||||
this.updateBak();
|
||||
return;
|
||||
}
|
||||
if (typeof this.fileContent[this.fileId] !== "undefined") {
|
||||
this.contentDetail = this.fileContent[this.fileId];
|
||||
this.updateBak();
|
||||
return;
|
||||
}
|
||||
if (['word', 'excel', 'ppt'].includes(this.file.type)) {
|
||||
@@ -309,10 +305,6 @@ export default {
|
||||
case 'flow':
|
||||
this.$refs.myFlow[act == 'pdf' ? 'exportPDF' : 'exportPNG'](this.file.name, 3);
|
||||
break;
|
||||
|
||||
case 'sheet':
|
||||
this.$refs.mySheet.exportExcel(this.file.name, act);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -11,18 +11,12 @@
|
||||
<Icon v-else type="ios-refresh" @click="getContent" />
|
||||
</div>
|
||||
</div>
|
||||
<Dropdown v-if="file.type=='mind' || file.type=='flow' || file.type=='sheet'"
|
||||
<Dropdown v-if="file.type=='mind' || file.type=='flow'"
|
||||
trigger="click"
|
||||
class="header-hint"
|
||||
@on-click="exportMenu">
|
||||
<a href="javascript:void(0)">{{$L('导出')}}<Icon type="ios-arrow-down"></Icon></a>
|
||||
<DropdownMenu v-if="file.type=='sheet'" slot="list">
|
||||
<DropdownItem name="xlsx">{{$L('导出XLSX')}}</DropdownItem>
|
||||
<DropdownItem name="xlml">{{$L('导出XLS')}}</DropdownItem>
|
||||
<DropdownItem name="csv">{{$L('导出CSV')}}</DropdownItem>
|
||||
<DropdownItem name="txt">{{$L('导出TXT')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu v-else slot="list">
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem name="png">{{$L('导出PNG图片')}}</DropdownItem>
|
||||
<DropdownItem name="pdf">{{$L('导出PDF文件')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
@@ -35,8 +29,8 @@
|
||||
</template>
|
||||
<Flow v-else-if="file.type=='flow'" ref="myFlow" v-model="contentDetail" readOnly/>
|
||||
<Minder v-else-if="file.type=='mind'" ref="myMind" v-model="contentDetail" readOnly/>
|
||||
<LuckySheet v-else-if="file.type=='sheet'" ref="mySheet" v-model="contentDetail" readOnly/>
|
||||
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :code="code" readOnly/>
|
||||
<AceEditor v-else-if="['code', 'txt'].includes(file.type)" v-model="contentDetail.content" :ext="file.ext" readOnly/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="contentLoad" class="content-load"><Loading/></div>
|
||||
@@ -50,13 +44,13 @@ Vue.use(Minder)
|
||||
|
||||
const MDPreview = () => import('../../../components/MDEditor/preview');
|
||||
const TEditor = () => import('../../../components/TEditor');
|
||||
const LuckySheet = () => import('../../../components/LuckySheet');
|
||||
const Flow = () => import('../../../components/Flow');
|
||||
const AceEditor = () => import('../../../components/AceEditor');
|
||||
const OnlyOffice = () => import('../../../components/OnlyOffice');
|
||||
|
||||
export default {
|
||||
name: "FilePreview",
|
||||
components: {TEditor, MDPreview, LuckySheet, Flow, OnlyOffice},
|
||||
components: {AceEditor, TEditor, MDPreview, Flow, OnlyOffice},
|
||||
props: {
|
||||
code: {
|
||||
type: String,
|
||||
@@ -159,10 +153,6 @@ export default {
|
||||
case 'flow':
|
||||
this.$refs.myFlow[act == 'pdf' ? 'exportPDF' : 'exportPNG'](this.file.name, 3);
|
||||
break;
|
||||
|
||||
case 'sheet':
|
||||
this.$refs.mySheet.exportExcel(this.file.name, act);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</ETooltip>
|
||||
</li>
|
||||
<li :class="['project-icon', searchText!='' ? 'active' : '']">
|
||||
<Tooltip :always="searchText!=''" @on-popper-show="searchFocus" theme="light">
|
||||
<Tooltip :always="searchAlways" @on-popper-show="searchFocus" theme="light">
|
||||
<Icon class="menu-icon" type="ios-search" @click="searchFocus" />
|
||||
<div slot="content">
|
||||
<Input v-model="searchText" ref="searchInput" :placeholder="$L('名称、描述...')" class="search-input" clearable/>
|
||||
@@ -550,6 +550,17 @@ export default {
|
||||
|
||||
...mapGetters(['projectData', 'projectParameter', 'transforTasks']),
|
||||
|
||||
searchAlways() {
|
||||
return !(!this.searchText
|
||||
|| this.settingShow
|
||||
|| this.userShow
|
||||
|| this.inviteShow
|
||||
|| this.transferShow
|
||||
|| this.workflowShow
|
||||
|| this.logShow
|
||||
|| this.archivedTaskShow);
|
||||
},
|
||||
|
||||
userWaitRemove() {
|
||||
const {userids, useridbak} = this.userData;
|
||||
if (!userids) {
|
||||
|
||||
@@ -216,11 +216,14 @@ export default {
|
||||
return list
|
||||
}
|
||||
if (this.taskId > 0 && $A.isJson(record.flow)) {
|
||||
list.push({
|
||||
id,
|
||||
button: '重置',
|
||||
content: `确定重置为【${$A.getMiddle(record.flow.flow_item_name, "|")}】吗?`,
|
||||
})
|
||||
let name = $A.getMiddle(record.flow.flow_item_name, "|")
|
||||
if (name) {
|
||||
list.push({
|
||||
id,
|
||||
button: '重置',
|
||||
content: `确定重置为【${name}】吗?`,
|
||||
})
|
||||
}
|
||||
}
|
||||
return list;
|
||||
},
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
<li v-for="file in fileList">
|
||||
<img v-if="file.id" class="file-ext" :src="file.thumb"/>
|
||||
<Loading v-else class="file-load"/>
|
||||
<a class="file-name" :href="file.path||'javascript:;'" target="_blank">{{file.name}}</a>
|
||||
<div class="file-name" @click="downFile(file)">{{file.name}}</div>
|
||||
<div class="file-size">{{$A.bytesToSize(file.size)}}</div>
|
||||
<EPopover v-model="file._deling" class="file-delete">
|
||||
<div class="task-detail-delete-file-popover">
|
||||
@@ -517,6 +517,7 @@ export default {
|
||||
computed: {
|
||||
...mapState([
|
||||
'userId',
|
||||
'userToken',
|
||||
'cacheProjects',
|
||||
'cacheColumns',
|
||||
'cacheTasks',
|
||||
@@ -916,7 +917,7 @@ export default {
|
||||
|
||||
onAddsub() {
|
||||
if (this.addsubName == '') {
|
||||
$A.messageSuccess('任务描述不能为空');
|
||||
$A.messageError('任务描述不能为空');
|
||||
return;
|
||||
}
|
||||
this.addsubLoad++;
|
||||
@@ -1131,6 +1132,17 @@ export default {
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
|
||||
downFile(file) {
|
||||
$A.modalConfirm({
|
||||
title: '下载文件',
|
||||
content: `${file.name} (${$A.bytesToSize(file.size)})`,
|
||||
okText: '立即下载',
|
||||
onOk: () => {
|
||||
$A.downFile($A.apiUrl(`project/task/filedown?file_id=${file.id}&token=${this.userToken}`))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,14 @@
|
||||
</template>
|
||||
|
||||
<div class="file-menu" :style="contextMenuStyles">
|
||||
<Dropdown trigger="custom" :visible="contextMenuVisible" transfer @on-clickoutside="handleClickContextMenuOutside" @on-visible-change="handleVisibleChangeMenu">
|
||||
<DropdownMenu slot="list" class="page-file-dropdown-menu">
|
||||
<Dropdown
|
||||
trigger="custom"
|
||||
:visible="contextMenuVisible"
|
||||
transfer-class-name="page-file-dropdown-menu"
|
||||
@on-clickoutside="handleClickContextMenuOutside"
|
||||
@on-visible-change="handleVisibleChangeMenu"
|
||||
transfer>
|
||||
<DropdownMenu slot="list">
|
||||
<template v-if="contextMenuItem.id">
|
||||
<DropdownItem @click.native="handleContextClick('open')">{{$L('打开')}}</DropdownItem>
|
||||
<Dropdown placement="right-start" transfer>
|
||||
@@ -133,6 +139,7 @@
|
||||
<template v-else-if="contextMenuItem.share">
|
||||
<DropdownItem @click.native="handleContextClick('outshare')" divided>{{$L('退出共享')}}</DropdownItem>
|
||||
</template>
|
||||
<DropdownItem @click.native="handleContextClick('download')" :disabled="contextMenuItem.ext == ''">{{$L('下载')}}</DropdownItem>
|
||||
<DropdownItem @click.native="handleContextClick('delete')" divided style="color:red">{{$L('删除')}}</DropdownItem>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -153,12 +160,12 @@
|
||||
<div v-if="uploadShow && uploadList.length > 0" class="file-upload-list">
|
||||
<div class="upload-wrap">
|
||||
<div class="title">
|
||||
{{$L('上传列表')}}
|
||||
{{$L('上传列表')}} ({{uploadList.length}})
|
||||
<em v-if="uploadList.find(({status}) => status === 'finished')" @click="uploadClear">{{$L('清空已完成')}}</em>
|
||||
</div>
|
||||
<ul class="content">
|
||||
<li v-for="(item, index) in uploadList">
|
||||
<AutoTip class="file-name">{{item.name}}</AutoTip>
|
||||
<li v-for="(item, index) in uploadList" :key="index" v-if="index < 100">
|
||||
<AutoTip class="file-name">{{uploadName(item)}}</AutoTip>
|
||||
<AutoTip v-if="item.status === 'finished' && item.response && item.response.ret !== 1" class="file-error">{{item.response.msg}}</AutoTip>
|
||||
<Progress v-else :percent="uploadPercentageParse(item.percentage)" :stroke-width="5" />
|
||||
<Icon class="file-close" type="ios-close-circle-outline" @click="uploadList.splice(index, 1)"/>
|
||||
@@ -344,11 +351,6 @@ export default {
|
||||
"name": "文本",
|
||||
"divided": true
|
||||
},
|
||||
{
|
||||
"value": "sheet",
|
||||
"label": null,
|
||||
"name": "表格",
|
||||
},
|
||||
{
|
||||
"value": "flow",
|
||||
"label": "流程图",
|
||||
@@ -406,8 +408,13 @@ export default {
|
||||
'ofd',
|
||||
'pdf',
|
||||
'txt',
|
||||
'html', 'htm', 'asp', 'jsp', 'xml', 'json', 'properties', 'md', 'gitignore', 'log', 'java', 'py', 'c', 'cpp', 'sql', 'sh', 'bat', 'm', 'bas', 'prg', 'cmd',
|
||||
'php', 'go', 'python', 'js', 'ftl', 'css', 'lua', 'rb', 'yaml', 'yml', 'h', 'cs', 'aspx',
|
||||
'htaccess', 'htgroups', 'htpasswd', 'conf', 'bat', 'cmd', 'cpp', 'c', 'cc', 'cxx', 'h', 'hh', 'hpp', 'ino', 'cs', 'css',
|
||||
'dockerfile', 'go', 'html', 'htm', 'xhtml', 'vue', 'we', 'wpy', 'java', 'js', 'jsm', 'jsx', 'json', 'jsp', 'less', 'lua', 'makefile', 'gnumakefile',
|
||||
'ocamlmakefile', 'make', 'md', 'markdown', 'mysql', 'nginx', 'ini', 'cfg', 'prefs', 'm', 'mm', 'pl', 'pm', 'p6', 'pl6', 'pm6', 'pgsql', 'php',
|
||||
'inc', 'phtml', 'shtml', 'php3', 'php4', 'php5', 'phps', 'phpt', 'aw', 'ctp', 'module', 'ps1', 'py', 'r', 'rb', 'ru', 'gemspec', 'rake', 'guardfile', 'rakefile',
|
||||
'gemfile', 'rs', 'sass', 'scss', 'sh', 'bash', 'bashrc', 'sql', 'sqlserver', 'swift', 'ts', 'typescript', 'str', 'vbs', 'vb', 'v', 'vh', 'sv', 'svh', 'xml',
|
||||
'rdf', 'rss', 'wsdl', 'xslt', 'atom', 'mathml', 'mml', 'xul', 'xbl', 'xaml', 'yaml', 'yml',
|
||||
'asp', 'properties', 'gitignore', 'log', 'bas', 'prg', 'python', 'ftl', 'aspx',
|
||||
'mp3', 'wav', 'mp4', 'flv',
|
||||
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
|
||||
'xmind', 'rp',
|
||||
@@ -903,6 +910,21 @@ export default {
|
||||
this.linkGet()
|
||||
break;
|
||||
|
||||
case 'download':
|
||||
if (!item.ext) {
|
||||
$A.modalError("此文件不支持下载");
|
||||
return;
|
||||
}
|
||||
$A.modalConfirm({
|
||||
title: '下载文件',
|
||||
content: `${item.name}.${item.ext} (${$A.bytesToSize(item.size)})`,
|
||||
okText: '立即下载',
|
||||
onOk: () => {
|
||||
$A.downFile($A.apiUrl(`file/content?id=${item.id}&down=yes&token=${this.userToken}`))
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
let typeName = item.type == 'folder' ? '文件夹' : '文件';
|
||||
$A.modalConfirm({
|
||||
@@ -1142,6 +1164,10 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
uploadName(item) {
|
||||
return $A.getObject(item, 'response.data.full_name') || item.name
|
||||
},
|
||||
|
||||
/********************文件上传部分************************/
|
||||
|
||||
uploadUpdate(fileList) {
|
||||
|
||||
Reference in New Issue
Block a user