mirror of
https://github.com/marktext/marktext.git
synced 2025-05-16 17:00:30 +08:00
feat: doutu
This commit is contained in:
parent
fdf4873399
commit
ca9fc76d2b
@ -1,9 +1,11 @@
|
||||
### 0.6.10
|
||||
### 0.6.11
|
||||
|
||||
**Features**
|
||||
|
||||
- Add **dark** theme and **light** theme in both realtime preview mode and source code mode.
|
||||
|
||||
- Insert `doutu` into the document, use CMD + / to open the panel.
|
||||
|
||||
**Optimization**
|
||||
|
||||
- Customize the scroll bar background color and thumb color.
|
||||
|
16
package-lock.json
generated
16
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "marktext",
|
||||
"version": "0.3.1",
|
||||
"version": "0.6.10",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -550,11 +550,11 @@
|
||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.16.2.tgz",
|
||||
"integrity": "sha1-uk+S8XFn37q0CYN4VFS5rBScPG0=",
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
||||
"requires": {
|
||||
"follow-redirects": "1.2.6",
|
||||
"follow-redirects": "1.4.1",
|
||||
"is-buffer": "1.1.6"
|
||||
}
|
||||
},
|
||||
@ -5387,9 +5387,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.6.tgz",
|
||||
"integrity": "sha512-FrMqZ/FONtHnbqO651UPpfRUVukIEwJhXMfdr/JWAmrDbeYBu773b1J6gdWDyRIj4hvvzQEHoEOTrdR8o6KLYA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz",
|
||||
"integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==",
|
||||
"requires": {
|
||||
"debug": "3.1.0"
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "marktext",
|
||||
"version": "0.6.10",
|
||||
"version": "0.6.11",
|
||||
"author": "Jocs <luoran1988@126.com>",
|
||||
"description": "A markdown editor",
|
||||
"license": "MIT",
|
||||
@ -68,7 +68,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.16.1",
|
||||
"axios": "^0.18.0",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"codemirror": "^5.31.0",
|
||||
"css-tree": "^1.0.0-alpha.27",
|
||||
|
@ -175,6 +175,35 @@ const formatCtrl = ContentState => {
|
||||
block.text = generator(tokens)
|
||||
}
|
||||
|
||||
ContentState.prototype.insertAidou = function (url) {
|
||||
const { start, end } = this.cursor
|
||||
const { key, offset: startOffset } = start
|
||||
const { offset: endOffset } = end
|
||||
const block = this.getBlock(key)
|
||||
const { text } = block
|
||||
if (key !== end.key) {
|
||||
block.text = text.substring(0, startOffset) + `` + text.substring(startOffset)
|
||||
const offset = startOffset + 2
|
||||
this.cursor = {
|
||||
start: { key, offset },
|
||||
end: { key, offset }
|
||||
}
|
||||
} else {
|
||||
block.text = text.substring(0, start.offset) + `` + text.substring(end.offset)
|
||||
this.cursor = {
|
||||
start: {
|
||||
key,
|
||||
offset: startOffset + 2
|
||||
},
|
||||
end: {
|
||||
key,
|
||||
offset: startOffset + 2 + text.substring(startOffset, endOffset).length
|
||||
}
|
||||
}
|
||||
}
|
||||
this.render()
|
||||
}
|
||||
|
||||
ContentState.prototype.format = function (type) {
|
||||
const { start, end } = selection.getCursorRange()
|
||||
const startBlock = this.getBlock(start.key)
|
||||
|
@ -454,6 +454,10 @@ class Aganippe {
|
||||
this.contentState.format(type)
|
||||
}
|
||||
|
||||
insertAidou (url) {
|
||||
this.contentState.insertAidou(url)
|
||||
}
|
||||
|
||||
search (value, opt) {
|
||||
const { selectHighlight } = opt
|
||||
this.contentState.search(value, opt)
|
||||
|
@ -16,6 +16,9 @@ const createWindow = (pathname, options = {}) => {
|
||||
|
||||
const { x, y, width, height } = mainWindowState
|
||||
const winOpt = Object.assign({ x, y, width, height }, {
|
||||
webPreferences: {
|
||||
webSecurity: false
|
||||
},
|
||||
useContentSize: true,
|
||||
show: false,
|
||||
frame: false,
|
||||
|
@ -58,5 +58,13 @@ export default {
|
||||
click: (menuItem, browserWindow) => {
|
||||
actions.edit(browserWindow, 'replace')
|
||||
}
|
||||
}, {
|
||||
type: 'separator'
|
||||
}, {
|
||||
label: 'Aidou',
|
||||
accelerator: 'CmdOrCtrl+/',
|
||||
click: (menuItem, browserWindow) => {
|
||||
actions.edit(browserWindow, 'aidou')
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ export default {
|
||||
submenu: [{
|
||||
label: 'Dark',
|
||||
type: 'radio',
|
||||
checked: true,
|
||||
checked: false,
|
||||
click (menuItem, browserWindow) {
|
||||
actions.selectTheme(browserWindow, 'dark')
|
||||
}
|
||||
}, {
|
||||
label: 'Light',
|
||||
type: 'radio',
|
||||
checked: false,
|
||||
checked: true,
|
||||
click (menuItem, browserWindow) {
|
||||
actions.selectTheme(browserWindow, 'light')
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -54,11 +54,15 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<aidou
|
||||
@select="handleSelect"
|
||||
></aidou>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Aganippe from '../../editor'
|
||||
import aidou from './aidou/aidou.vue'
|
||||
import bus from '../bus'
|
||||
import { animatedScrollTo } from '../../editor/utils'
|
||||
|
||||
@ -69,6 +73,9 @@
|
||||
]
|
||||
|
||||
export default {
|
||||
components: {
|
||||
aidou
|
||||
},
|
||||
props: {
|
||||
typewriter: {
|
||||
type: Boolean,
|
||||
@ -166,6 +173,9 @@
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleSelect (url) {
|
||||
this.editor && this.editor.insertAidou(url)
|
||||
},
|
||||
handleSearch (value, opt) {
|
||||
const searchMatches = this.editor.search(value, opt)
|
||||
this.$store.dispatch('SEARCH', searchMatches)
|
||||
|
184
src/renderer/components/aidou/aidou.vue
Normal file
184
src/renderer/components/aidou/aidou.vue
Normal file
@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<div class="aidou">
|
||||
<el-dialog
|
||||
:visible.sync="showAiDou"
|
||||
:show-close="false"
|
||||
:modal="true"
|
||||
custom-class="ag-dialog-table"
|
||||
width="610px"
|
||||
|
||||
>
|
||||
<div slot="title" class="search-wrapper">
|
||||
<svg class="icon" aria-hidden="true" @click="shuffle">
|
||||
<use xlink:href="#icon-shuffle"></use>
|
||||
</svg>
|
||||
<input type="text" v-model="query" class="search" @keyup.13="search" ref="search">
|
||||
<svg class="icon" aria-hidden="true" @click="search">
|
||||
<use xlink:href="#icon-search"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="image-container" ref="emojis">
|
||||
<div class="img-wrapper" v-for="(emoji, index) of aiList" :key="index" @click="handleEmojiClick(emoji)">
|
||||
<img :src="emoji.link" alt="" >
|
||||
</div>
|
||||
<loading v-if="aiLoading"></loading>
|
||||
</div>
|
||||
<!-- <div slot="footer" class="dialog-footer">
|
||||
<el-button @click="showAiDou = false" size="mini">
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-close"></use>
|
||||
</svg>
|
||||
</el-button>
|
||||
</div> -->
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bus from '../../bus'
|
||||
import loading from './loading.vue'
|
||||
import { mapState } from 'vuex'
|
||||
import hotWords from './hotWords'
|
||||
import resource from '../../store/resource'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
loading
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showAiDou: false,
|
||||
query: '',
|
||||
page: 1,
|
||||
size: 24,
|
||||
bindScroll: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$nextTick(() => {
|
||||
bus.$on('aidou', this.handleShowAiDou)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
const container = this.$refs.emojis
|
||||
container.removeEventListener('scroll', this.handlerScroll)
|
||||
},
|
||||
computed: {
|
||||
...mapState([
|
||||
'aiLoading', 'aiList'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
async handleEmojiClick ({ link }) {
|
||||
try {
|
||||
const base64 = await resource.fetchImgToBase64(link)
|
||||
const { url } = await resource.sm(base64)
|
||||
this.$emit('select', url)
|
||||
this.showAiDou = false
|
||||
} catch (err) {
|
||||
// todo handle error
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
handleShowAiDou () {
|
||||
this.showAiDou = true
|
||||
if (!this.bindScroll) {
|
||||
this.$nextTick(() => {
|
||||
const container = this.$refs.emojis
|
||||
container.addEventListener('scroll', this.handlerScroll)
|
||||
this.bindScroll = true
|
||||
})
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.search.focus()
|
||||
})
|
||||
},
|
||||
handlerScroll (event) {
|
||||
const container = this.$refs.emojis
|
||||
const { offsetHeight, scrollHeight, scrollTop } = container
|
||||
if (scrollHeight - scrollTop - offsetHeight <= 100 && !this.aiLoading) {
|
||||
this.loadMore()
|
||||
}
|
||||
},
|
||||
search () {
|
||||
const { query, size } = this
|
||||
const page = this.page = 1
|
||||
const type = 'search'
|
||||
const params = { query, size, page }
|
||||
this.$store.dispatch('AI_SEARCH', { params, type })
|
||||
},
|
||||
loadMore () {
|
||||
const { query, size, page } = this
|
||||
const params = { query, size, page: page + 1 }
|
||||
this.$store.dispatch('AI_SEARCH', { params, type: 'loadMore' })
|
||||
},
|
||||
shuffle () {
|
||||
const luckWord = hotWords[Math.random() * hotWords.length | 0]
|
||||
this.query = luckWord
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search-wrapper {
|
||||
max-width: 410px;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
padding: 5px;
|
||||
background: #fff;
|
||||
box-shadow: 0 3px 8px rgba(0,0,0,.1);
|
||||
border: 1px solid #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.search {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
outline: none;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
padding: 0 8px;
|
||||
margin: 0 10px;
|
||||
color: #606266;
|
||||
}
|
||||
.search-wrapper svg {
|
||||
cursor: pointer;
|
||||
margin: 0 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
color: #606266;
|
||||
}
|
||||
.image-container {
|
||||
height: 410px;
|
||||
overflow: auto;
|
||||
}
|
||||
.image-container .img-wrapper {
|
||||
overflow: hidden;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all .25s ease-in-out;
|
||||
display: inline-block;
|
||||
}
|
||||
.image-container .img-wrapper img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.image-container .img-wrapper:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.image-container .img-wrapper:nth-of-type(4n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
117
src/renderer/components/aidou/hotWords.js
Normal file
117
src/renderer/components/aidou/hotWords.js
Normal file
@ -0,0 +1,117 @@
|
||||
export default [
|
||||
'bug',
|
||||
'代码有毒',
|
||||
'大佬',
|
||||
'hentai',
|
||||
'变态',
|
||||
'40米',
|
||||
'哈哈',
|
||||
'嘿嘿',
|
||||
'滑稽',
|
||||
'原谅',
|
||||
'喜欢',
|
||||
'秋裤',
|
||||
'盒子精',
|
||||
'吃鸡',
|
||||
'阿卡林',
|
||||
'元旦快乐',
|
||||
'新年快乐',
|
||||
'康娜',
|
||||
'赞',
|
||||
'2b',
|
||||
'正面上我',
|
||||
'bilibili',
|
||||
'胖次',
|
||||
'飞机',
|
||||
'哲学',
|
||||
'鸡鸡',
|
||||
'2233',
|
||||
'233',
|
||||
'蕾姆',
|
||||
'拉姆',
|
||||
'niconiconi',
|
||||
'图样图森破',
|
||||
'非战斗人员',
|
||||
'天依',
|
||||
'绅士',
|
||||
'今天的风儿',
|
||||
'战5渣',
|
||||
'楼上',
|
||||
'楼下',
|
||||
'女装',
|
||||
'吸猫',
|
||||
'二次元',
|
||||
'新吧唧',
|
||||
'poi',
|
||||
'提督',
|
||||
'咸鱼',
|
||||
'滴滴',
|
||||
'老司机',
|
||||
'香菜',
|
||||
'金馆长',
|
||||
'笑',
|
||||
'机智',
|
||||
'撩',
|
||||
'套路',
|
||||
'洪荒之力',
|
||||
'傲娇',
|
||||
'一言不合',
|
||||
'百合',
|
||||
'白学家',
|
||||
'电学',
|
||||
'白色相册',
|
||||
'诚哥',
|
||||
'本子',
|
||||
'香蕉君',
|
||||
'金坷垃',
|
||||
'舰娘',
|
||||
'圣杯',
|
||||
'呆毛',
|
||||
'咖喱棒',
|
||||
'金闪闪',
|
||||
'吃土',
|
||||
'小目标',
|
||||
'FFF团',
|
||||
'友谊的小船',
|
||||
'狗带',
|
||||
'没想到你是这样的',
|
||||
'懵逼',
|
||||
'我好方',
|
||||
'辣眼睛',
|
||||
'猴赛雷',
|
||||
'吓死宝宝了',
|
||||
'宝宝',
|
||||
'咋不上天',
|
||||
'重要的事',
|
||||
'城会玩',
|
||||
'A4腰',
|
||||
'城会玩',
|
||||
'厉害了我的哥',
|
||||
'感觉身体被掏空',
|
||||
'互相伤害',
|
||||
'北京瘫',
|
||||
'葛优躺',
|
||||
'一颗赛艇',
|
||||
'因吹斯汀',
|
||||
'醒醒',
|
||||
'社会我',
|
||||
'萝莉',
|
||||
'御姐',
|
||||
'正太',
|
||||
'Loli',
|
||||
'单身狗',
|
||||
'逗比',
|
||||
'坟头草',
|
||||
'你开心',
|
||||
'裤子都脱了',
|
||||
'算我输',
|
||||
'修仙',
|
||||
'老哥稳',
|
||||
'奶子',
|
||||
'小姐姐',
|
||||
'石乐志',
|
||||
'皮皮虾我们走',
|
||||
'我们走',
|
||||
'小拳拳',
|
||||
'把我的意大利'
|
||||
]
|
94
src/renderer/components/aidou/loading.vue
Normal file
94
src/renderer/components/aidou/loading.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="cpt-loading">
|
||||
<div class="loader">
|
||||
<span v-for="i in 3" :key="i" :style="dotSize"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
size: {
|
||||
type: Number,
|
||||
default: 14
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
dotSize () {
|
||||
const size = `${this.size}px`
|
||||
return {
|
||||
width: size,
|
||||
height: size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.cpt-loading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.loader {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loader span {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
animation: 3s infinite linear;
|
||||
}
|
||||
.loader span:nth-child(1) {
|
||||
background: #F2F6FC;
|
||||
animation: kiri 1.2s infinite linear;
|
||||
}
|
||||
.loader span:nth-child(2) {
|
||||
z-index: 100;
|
||||
background: #EBEEF5;
|
||||
}
|
||||
.loader span:nth-child(3) {
|
||||
background: #C0C4CC;
|
||||
animation: kanan 1.2s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes kanan {
|
||||
0% {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
100% {
|
||||
z-index: 200;
|
||||
|
||||
transform: translateX(20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes kiri {
|
||||
0% {
|
||||
z-index: 200;
|
||||
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
}
|
||||
</style>
|
38
src/renderer/store/aidou.js
Normal file
38
src/renderer/store/aidou.js
Normal file
@ -0,0 +1,38 @@
|
||||
import resource from './resource'
|
||||
|
||||
const state = {
|
||||
aiLoading: false,
|
||||
aiList: []
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_AI_LIST (state, { data, type }) {
|
||||
console.log(type)
|
||||
if (type === 'search') {
|
||||
state.aiList = data
|
||||
} else {
|
||||
state.aiList = [...state.aiList, ...data]
|
||||
}
|
||||
},
|
||||
SET_AI_STATUS (state, bool) {
|
||||
state.aiLoading = bool
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
AI_SEARCH ({ commit }, { params, type }) {
|
||||
commit('SET_AI_STATUS', true)
|
||||
return resource.sogou(params)
|
||||
.then(({ data, total }) => {
|
||||
commit('SET_AI_LIST', { data, type })
|
||||
commit('SET_AI_STATUS', false)
|
||||
return { data, total }
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
commit('SET_AI_STATUS', false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default { state, mutations, actions }
|
@ -2,11 +2,13 @@ import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import editorStore from './editor'
|
||||
import aidouStore from './aidou'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const storeArray = [
|
||||
editorStore
|
||||
editorStore,
|
||||
aidouStore
|
||||
]
|
||||
|
||||
const { actions, mutations, state } = storeArray.reduce((acc, s) => {
|
||||
|
63
src/renderer/store/resource.js
Normal file
63
src/renderer/store/resource.js
Normal file
@ -0,0 +1,63 @@
|
||||
import axios from 'axios'
|
||||
import { serialize, merge, dataURItoBlob } from '../util'
|
||||
|
||||
const CONFIG = {
|
||||
SOGOU: {
|
||||
API: 'https://pic.sogou.com/pics/json.jsp',
|
||||
PARAMS: {
|
||||
query: '',
|
||||
st: 5,
|
||||
start: 0,
|
||||
xml_len: 100,
|
||||
reqFrom: 'wap_result'
|
||||
},
|
||||
HOT_SEARCH: 'https://pic.sogou.com/pic/emo/'
|
||||
}
|
||||
}
|
||||
|
||||
const resource = {
|
||||
sogou ({ query, page, size }) {
|
||||
const api = CONFIG.SOGOU.API
|
||||
const defParams = CONFIG.SOGOU.PARAMS
|
||||
const params = merge(defParams, {
|
||||
query: `${query} 表情`,
|
||||
start: (page - 1) * size,
|
||||
xml_len: size
|
||||
})
|
||||
const queryURL = `${api}?${serialize(params)}`
|
||||
return axios.get(queryURL, { withCredentials: true }).then(({ data = {} }) => {
|
||||
console.log(data)
|
||||
return {
|
||||
data: (data.items || []).map(it => ({
|
||||
link: it.locImageLink,
|
||||
suffix: it.type
|
||||
})),
|
||||
total: data.totalNum || 0
|
||||
}
|
||||
})
|
||||
},
|
||||
fetchImgToBase64 (url) {
|
||||
return axios.get(url, { responseType: 'blob' })
|
||||
.then(({ data }) => new Promise((resolve, reject) => {
|
||||
const reader = new window.FileReader()
|
||||
reader.onloadend = () => resolve(reader.result)
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(data)
|
||||
}))
|
||||
},
|
||||
sm (base64) {
|
||||
const api = 'https://sm.ms/api/upload'
|
||||
const data = new window.FormData()
|
||||
data.append('smfile', dataURItoBlob(base64, 'temp.png'))
|
||||
return axios.post(api, data).then(({ data }) => {
|
||||
const { data: res } = data
|
||||
return {
|
||||
url: res.url,
|
||||
err: '',
|
||||
server: 'sm'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default resource
|
17
src/renderer/util/index.js
Normal file
17
src/renderer/util/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
export function serialize (params) {
|
||||
return Object.keys(params).map(key => `${key}=${params[key]}`).join('&')
|
||||
}
|
||||
export function merge (...args) {
|
||||
return Object.assign({}, ...args)
|
||||
}
|
||||
export function dataURItoBlob (dataURI) {
|
||||
const data = dataURI.split(';base64,')
|
||||
const byte = window.atob(data[1])
|
||||
const mime = data[0].split(':')[1]
|
||||
const ab = new ArrayBuffer(byte.length)
|
||||
const ia = new Uint8Array(ab)
|
||||
for (let i = 0; i < byte.length; i++) {
|
||||
ia[i] = byte.charCodeAt(i)
|
||||
}
|
||||
return new window.Blob([ab], { type: mime })
|
||||
}
|
Loading…
Reference in New Issue
Block a user