支持自定义图床
This commit is contained in:
parent
cc6c8ff5ab
commit
cb1354516f
6
package-lock.json
generated
6
package-lock.json
generated
@ -11267,6 +11267,12 @@
|
|||||||
"nopt": "~3.0.1"
|
"nopt": "~3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"js-md5": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||||
|
@ -100,6 +100,7 @@
|
|||||||
"jest": "^23.0.0",
|
"jest": "^23.0.0",
|
||||||
"jest-raw-loader": "^1.0.1",
|
"jest-raw-loader": "^1.0.1",
|
||||||
"jest-serializer-vue": "^0.3.0",
|
"jest-serializer-vue": "^0.3.0",
|
||||||
|
"js-md5": "^0.7.3",
|
||||||
"node-sass": "^4.0.0",
|
"node-sass": "^4.0.0",
|
||||||
"npm-bump": "^0.0.23",
|
"npm-bump": "^0.0.23",
|
||||||
"offline-plugin": "^5.0.3",
|
"offline-plugin": "^5.0.3",
|
||||||
|
3
src/assets/iconCustom.svg
Normal file
3
src/assets/iconCustom.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg t="1657361174041" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4922" width="32" height="32">
|
||||||
|
<path d="M259.072 303.104q30.72 0 52.736 22.016t22.016 53.76q0 30.72-22.016 52.736t-52.736 22.016q-31.744 0-53.248-22.016t-21.504-52.736q0-31.744 21.504-53.76t53.248-22.016zM864.256 57.344q43.008 0 69.12 28.672t26.112 65.536l0 550.912q0 23.552-16.896 39.936t-40.448 16.384l-70.656 0 0-123.904 44.032 0q11.264 0 19.456-8.192t8.192-20.48q0-11.264-8.192-19.456t-19.456-8.192l-44.032 0 0-79.872 44.032 0q11.264 0 19.456-8.192t8.192-19.456-8.192-19.968-19.456-8.704l-44.032 0 0-72.704 44.032 0q11.264 0 19.456-8.192t8.192-20.48q0-11.264-8.192-19.456t-19.456-8.192l-44.032 0 0-86.016q0-57.344-26.624-80.896t-90.112-23.552l-394.24 0 0-9.216q0-23.552 16.896-39.936t40.448-16.384l486.4 0zM692.224 184.32q39.936 0 57.856 23.04t17.92 59.904l0 565.248q0 23.552-19.456 43.52t-48.128 19.968l-572.416 0q-24.576 0-44.032-20.48t-19.456-48.128l0-575.488q0-29.696 16.384-48.64t43.008-18.944l568.32 0zM703.488 291.84q0-17.408-10.752-30.208t-34.304-12.8l-488.448 0q-4.096 0-11.264 1.536t-14.336 5.12-12.288 9.728-5.12 15.36l0 274.432q8.192 9.216 23.04 22.016t34.816 23.552 44.544 18.432 53.248 7.68q43.008 0 75.264-13.824t59.904-34.816 54.272-45.056 58.88-45.568 73.728-36.352 98.816-16.896l0-142.336z" p-id="4923" fill="#1296db"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -80,6 +80,7 @@ import ZendeskPublishModal from './modals/providers/ZendeskPublishModal';
|
|||||||
import CouchdbWorkspaceModal from './modals/providers/CouchdbWorkspaceModal';
|
import CouchdbWorkspaceModal from './modals/providers/CouchdbWorkspaceModal';
|
||||||
import CouchdbCredentialsModal from './modals/providers/CouchdbCredentialsModal';
|
import CouchdbCredentialsModal from './modals/providers/CouchdbCredentialsModal';
|
||||||
import SmmsAccountModal from './modals/providers/SmmsAccountModal';
|
import SmmsAccountModal from './modals/providers/SmmsAccountModal';
|
||||||
|
import CustomAccountModal from './modals/providers/CustomAccountModal';
|
||||||
|
|
||||||
const getTabbables = container => container.querySelectorAll('a[href], button, .textfield, input[type=checkbox]')
|
const getTabbables = container => container.querySelectorAll('a[href], button, .textfield, input[type=checkbox]')
|
||||||
// Filter enabled and visible element
|
// Filter enabled and visible element
|
||||||
@ -143,6 +144,7 @@ export default {
|
|||||||
CouchdbWorkspaceModal,
|
CouchdbWorkspaceModal,
|
||||||
CouchdbCredentialsModal,
|
CouchdbCredentialsModal,
|
||||||
SmmsAccountModal,
|
SmmsAccountModal,
|
||||||
|
CustomAccountModal,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<div class="modal__image">
|
<div class="modal__image">
|
||||||
<icon-key></icon-key>
|
<icon-key></icon-key>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="entries.length">Stackedit可以访问以下外部账号:</p>
|
<p v-if="entries.length">StackEdit中文版可以访问以下外部账号:</p>
|
||||||
<p v-else>Stackedit尚未访问任何外部账号。</p>
|
<p v-else>StackEdit中文版尚未访问任何外部账号。</p>
|
||||||
<div>
|
<div>
|
||||||
<div class="account-entry flex flex--column" v-for="entry in entries" :key="entry.token.sub">
|
<div class="account-entry flex flex--column" v-for="entry in entries" :key="entry.token.sub">
|
||||||
<div class="account-entry__header flex flex--row flex--align-center">
|
<div class="account-entry__header flex flex--row flex--align-center">
|
||||||
@ -30,6 +30,14 @@
|
|||||||
<b>URL:</b>
|
<b>URL:</b>
|
||||||
{{entry.url}}
|
{{entry.url}}
|
||||||
</span>
|
</span>
|
||||||
|
<span class="account-entry__field line-entry" v-if="entry.customHeaders">
|
||||||
|
<b>自定义请求头:</b>
|
||||||
|
{{entry.customHeaders}}
|
||||||
|
</span>
|
||||||
|
<span class="account-entry__field line-entry" v-if="entry.customParams">
|
||||||
|
<b>自定义Form参数:</b>
|
||||||
|
{{entry.customParams}}
|
||||||
|
</span>
|
||||||
<span class="account-entry__field" v-if="entry.scopes">
|
<span class="account-entry__field" v-if="entry.scopes">
|
||||||
<b>权限范围:</b>
|
<b>权限范围:</b>
|
||||||
{{entry.scopes.join(', ')}}
|
{{entry.scopes.join(', ')}}
|
||||||
@ -81,6 +89,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
||||||
<span>添加SM.MS账号</span>
|
<span>添加SM.MS账号</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
|
<menu-entry @click.native="addCustomAccount">
|
||||||
|
<icon-provider slot="icon" provider-id="custom"></icon-provider>
|
||||||
|
<span>添加自定义图床账号</span>
|
||||||
|
</menu-entry>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
<button class="button button--resolve" @click="config.resolve()">关闭</button>
|
<button class="button button--resolve" @click="config.resolve()">关闭</button>
|
||||||
@ -103,6 +115,7 @@ import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
|||||||
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
import wordpressHelper from '../../services/providers/helpers/wordpressHelper';
|
||||||
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
import zendeskHelper from '../../services/providers/helpers/zendeskHelper';
|
||||||
import smmsHelper from '../../services/providers/helpers/smmsHelper';
|
import smmsHelper from '../../services/providers/helpers/smmsHelper';
|
||||||
|
import customHelper from '../../services/providers/helpers/customHelper';
|
||||||
import badgeSvc from '../../services/badgeSvc';
|
import badgeSvc from '../../services/badgeSvc';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -188,6 +201,16 @@ export default {
|
|||||||
name: token.name,
|
name: token.name,
|
||||||
scopes: ['api'],
|
scopes: ['api'],
|
||||||
})),
|
})),
|
||||||
|
...Object.values(store.getters['data/customTokensBySub']).map(token => ({
|
||||||
|
token,
|
||||||
|
providerId: 'custom',
|
||||||
|
url: token.uploadUrl,
|
||||||
|
userId: token.name,
|
||||||
|
name: token.name,
|
||||||
|
customHeaders: token.customHeaders && JSON.stringify(token.customHeaders),
|
||||||
|
customParams: token.customParams && JSON.stringify(token.customParams),
|
||||||
|
scopes: ['upload'],
|
||||||
|
})),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -263,6 +286,12 @@ export default {
|
|||||||
await smmsHelper.addAccount(proxyUrl, apiSecretToken);
|
await smmsHelper.addAccount(proxyUrl, apiSecretToken);
|
||||||
} catch (e) { /* cancel */ }
|
} catch (e) { /* cancel */ }
|
||||||
},
|
},
|
||||||
|
async addCustomAccount() {
|
||||||
|
try {
|
||||||
|
const accountInfo = await store.dispatch('modal/open', { type: 'customAccount' });
|
||||||
|
await customHelper.addAccount(accountInfo);
|
||||||
|
} catch (e) { /* cancel */ }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -270,6 +299,18 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../styles/variables.scss';
|
@import '../../styles/variables.scss';
|
||||||
|
|
||||||
|
.line-entry {
|
||||||
|
word-break: break-word; /* 文本行的任意字内断开,就算是一个单词也会分开 */
|
||||||
|
word-wrap: break-word; /* IE */
|
||||||
|
white-space: -moz-pre-wrap; /* Mozilla */
|
||||||
|
white-space: -hp-pre-wrap; /* HP printers */
|
||||||
|
white-space: -o-pre-wrap; /* Opera 7 */
|
||||||
|
white-space: -pre-wrap; /* Opera 4-6 */
|
||||||
|
white-space: pre; /* CSS2 */
|
||||||
|
white-space: pre-wrap; /* CSS 2.1 */
|
||||||
|
white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
|
||||||
|
}
|
||||||
|
|
||||||
.account-entry {
|
.account-entry {
|
||||||
margin: 1.5em 0;
|
margin: 1.5em 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
@ -13,18 +13,21 @@
|
|||||||
<input slot="field" class="textfield" type="text" v-model.trim="url" @keydown.enter="resolve">
|
<input slot="field" class="textfield" type="text" v-model.trim="url" @keydown.enter="resolve">
|
||||||
</form-entry>
|
</form-entry>
|
||||||
<p>添加并选择图床后可实现粘贴/拖拽自动上传图片</p>
|
<p>添加并选择图床后可实现粘贴/拖拽自动上传图片</p>
|
||||||
<menu-entry @click.native="checkedImgDest(token.sub, 'smms')" v-for="token in smmsTokens" :key="token.sub">
|
<menu-entry @click.native="checkedImgDest(token.sub, token.providerId)" v-for="token in imageTokens" :key="token.sub">
|
||||||
<icon-check-circle v-if="checkedStorage.sub === token.sub" slot="icon"></icon-check-circle>
|
<icon-check-circle v-if="checkedStorage.sub === token.sub" slot="icon"></icon-check-circle>
|
||||||
<icon-check-circle-un v-if="checkedStorage.sub !== token.sub" slot="icon"></icon-check-circle-un>
|
<icon-check-circle-un v-if="checkedStorage.sub !== token.sub" slot="icon"></icon-check-circle-un>
|
||||||
<menu-item>
|
<menu-item>
|
||||||
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
<icon-provider slot="icon" :provider-id="token.providerId"></icon-provider>
|
||||||
<div>
|
<div>
|
||||||
SM.MS图床
|
{{ token.remark }}
|
||||||
<button class="menu-item__button button" @click.stop="remove('smms', token)" v-title="'删除'">
|
<button class="menu-item__button button" @click.stop="remove(token.providerId, token)" v-title="'删除'">
|
||||||
<icon-delete></icon-delete>
|
<icon-delete></icon-delete>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span>{{token.name}}</span>
|
<span>{{token.name}}</span>
|
||||||
|
<span class="line-entry" v-if="token.uploadUrl">上传地址:{{token.uploadUrl}}</span>
|
||||||
|
<span class="line-entry" v-if="token.headers">自定义请求头:{{token.headers}}</span>
|
||||||
|
<span class="line-entry" v-if="token.params">自定义Form参数:{{token.params}}</span>
|
||||||
</menu-item>
|
</menu-item>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
<menu-entry @click.native="checkedImgDest(tokenStorage.sid, 'gitea')" v-for="tokenStorage in giteaTokensImgStorages" :key="tokenStorage.sid">
|
<menu-entry @click.native="checkedImgDest(tokenStorage.sid, 'gitea')" v-for="tokenStorage in giteaTokensImgStorages" :key="tokenStorage.sid">
|
||||||
@ -44,6 +47,10 @@
|
|||||||
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
<icon-provider slot="icon" provider-id="smms"></icon-provider>
|
||||||
<span>添加SM.MS图床账号</span>
|
<span>添加SM.MS图床账号</span>
|
||||||
</menu-entry>
|
</menu-entry>
|
||||||
|
<menu-entry @click.native="addCustomAccount">
|
||||||
|
<icon-provider slot="icon" provider-id="custom"></icon-provider>
|
||||||
|
<span>添加自定义图床账号</span>
|
||||||
|
</menu-entry>
|
||||||
<menu-entry @click.native="addGiteaImgStorage">
|
<menu-entry @click.native="addGiteaImgStorage">
|
||||||
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
<icon-provider slot="icon" provider-id="gitea"></icon-provider>
|
||||||
<span>添加Gitea图床仓库</span>
|
<span>添加Gitea图床仓库</span>
|
||||||
@ -63,6 +70,7 @@ import MenuItem from '../menus/common/MenuItem';
|
|||||||
import smmsHelper from '../../services/providers/helpers/smmsHelper';
|
import smmsHelper from '../../services/providers/helpers/smmsHelper';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
import giteaHelper from '../../services/providers/helpers/giteaHelper';
|
||||||
|
import customHelper from '../../services/providers/helpers/customHelper';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
|
|
||||||
export default modalTemplate({
|
export default modalTemplate({
|
||||||
@ -79,10 +87,21 @@ export default modalTemplate({
|
|||||||
checkedStorage() {
|
checkedStorage() {
|
||||||
return store.getters['img/getCheckedStorage'];
|
return store.getters['img/getCheckedStorage'];
|
||||||
},
|
},
|
||||||
smmsTokens() {
|
imageTokens() {
|
||||||
const smmsTokensBySub = store.getters['data/smmsTokensBySub'];
|
return [
|
||||||
return Object.values(smmsTokensBySub)
|
...Object.values(store.getters['data/smmsTokensBySub']).map(token => ({
|
||||||
.sort((token1, token2) => token1.name.localeCompare(token2.name));
|
...token,
|
||||||
|
providerId: 'smms',
|
||||||
|
remark: 'SM.MS图床',
|
||||||
|
})),
|
||||||
|
...Object.values(store.getters['data/customTokensBySub']).map(token => ({
|
||||||
|
...token,
|
||||||
|
providerId: 'custom',
|
||||||
|
headers: token.customHeaders && JSON.stringify(token.customHeaders),
|
||||||
|
params: token.customParams && JSON.stringify(token.customParams),
|
||||||
|
remark: '自定义图床',
|
||||||
|
})),
|
||||||
|
];
|
||||||
},
|
},
|
||||||
giteaTokensImgStorages() {
|
giteaTokensImgStorages() {
|
||||||
const giteaTokensBySub = store.getters['data/giteaTokensBySub'];
|
const giteaTokensBySub = store.getters['data/giteaTokensBySub'];
|
||||||
@ -118,17 +137,22 @@ export default modalTemplate({
|
|||||||
store.dispatch('notification/info', '暂无已选择的图床,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
store.dispatch('notification/info', '暂无已选择的图床,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currStorage.provider === 'smms') {
|
if (currStorage.provider === 'smms' || currStorage.provider === 'custom') {
|
||||||
const filterTokens = this.smmsTokens.filter(it => it.sub === currStorage.sub);
|
const filterTokens = this.imageTokens.filter(it => it.sub === currStorage.sub);
|
||||||
if (!filterTokens.length) {
|
if (!filterTokens.length) {
|
||||||
store.dispatch('notification/info', 'SMS图床已失效,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
store.dispatch('notification/info', '图床已失效,未自动上传图片!请选择图床后重新粘贴/拖拽图片!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const token = filterTokens[0];
|
const token = filterTokens[0];
|
||||||
this.url = await smmsHelper.uploadFile({
|
const helper = currStorage.provider === 'smms' ? smmsHelper : customHelper;
|
||||||
|
try {
|
||||||
|
this.url = await helper.uploadFile({
|
||||||
token,
|
token,
|
||||||
file: imgFile,
|
file: imgFile,
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
store.dispatch('notification/error', err);
|
||||||
|
}
|
||||||
} else if (currStorage.provider === 'gitea') {
|
} else if (currStorage.provider === 'gitea') {
|
||||||
const filterTokenStorages = this.giteaTokensImgStorages
|
const filterTokenStorages = this.giteaTokensImgStorages
|
||||||
.filter(it => it.sid === currStorage.sub);
|
.filter(it => it.sid === currStorage.sub);
|
||||||
@ -185,7 +209,7 @@ export default modalTemplate({
|
|||||||
async remove(proivderId, item) {
|
async remove(proivderId, item) {
|
||||||
try {
|
try {
|
||||||
await store.dispatch('modal/open', 'imgStorageDeletion');
|
await store.dispatch('modal/open', 'imgStorageDeletion');
|
||||||
if (proivderId === 'smms') {
|
if (proivderId === 'smms' || proivderId === 'custom') {
|
||||||
const tokensBySub = utils.deepCopy(store.getters[`data/${proivderId}TokensBySub`]);
|
const tokensBySub = utils.deepCopy(store.getters[`data/${proivderId}TokensBySub`]);
|
||||||
delete tokensBySub[item.sub];
|
delete tokensBySub[item.sub];
|
||||||
// 删除账号
|
// 删除账号
|
||||||
@ -203,6 +227,10 @@ export default modalTemplate({
|
|||||||
const { proxyUrl, apiSecretToken } = await store.dispatch('modal/open', { type: 'smmsAccount' });
|
const { proxyUrl, apiSecretToken } = await store.dispatch('modal/open', { type: 'smmsAccount' });
|
||||||
await smmsHelper.addAccount(proxyUrl, apiSecretToken);
|
await smmsHelper.addAccount(proxyUrl, apiSecretToken);
|
||||||
},
|
},
|
||||||
|
async addCustomAccount() {
|
||||||
|
const accountInfo = await store.dispatch('modal/open', { type: 'customAccount' });
|
||||||
|
await customHelper.addAccount(accountInfo);
|
||||||
|
},
|
||||||
async addGiteaImgStorage() {
|
async addGiteaImgStorage() {
|
||||||
try {
|
try {
|
||||||
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'giteaAccount' });
|
const { serverUrl, applicationId, applicationSecret } = await store.dispatch('modal/open', { type: 'giteaAccount' });
|
||||||
@ -239,6 +267,18 @@ export default modalTemplate({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.line-entry {
|
||||||
|
word-break: break-word; /* 文本行的任意字内断开,就算是一个单词也会分开 */
|
||||||
|
word-wrap: break-word; /* IE */
|
||||||
|
white-space: -moz-pre-wrap; /* Mozilla */
|
||||||
|
white-space: -hp-pre-wrap; /* HP printers */
|
||||||
|
white-space: -o-pre-wrap; /* Opera 7 */
|
||||||
|
white-space: -pre-wrap; /* Opera 4-6 */
|
||||||
|
white-space: pre; /* CSS2 */
|
||||||
|
white-space: pre-wrap; /* CSS 2.1 */
|
||||||
|
white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item__button {
|
.menu-item__button {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__info" v-if="publishLocations.length">
|
<div class="modal__info" v-if="publishLocations.length">
|
||||||
<b>Tip:</b> Removing a location won't delete any file.
|
<b>提示:</b> 删除位置不会删除任何文件。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__button-bar">
|
<div class="modal__button-bar">
|
||||||
|
109
src/components/modals/providers/CustomAccountModal.vue
Normal file
109
src/components/modals/providers/CustomAccountModal.vue
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<modal-inner aria-label="链接自定义图床账号">
|
||||||
|
<div class="modal__content">
|
||||||
|
<div class="modal__image">
|
||||||
|
<icon-provider provider-id="custom"></icon-provider>
|
||||||
|
</div>
|
||||||
|
<p>将您的<b>自定义图床</b>账号链接到<b>StackEdit</b>。</p>
|
||||||
|
<form-entry label="自定义标识" error="name">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="name" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
自定义标识如果一样会覆盖之前的自定义图床账号。
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="上传图片接口地址" error="uploadUrl">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="uploadUrl" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
填入您个人的图床上传接口地址,上传接口仅支持POST提交。
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="文件参数名" error="fileParamName">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="fileParamName" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
文件参数名如:file
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="自定义请求头配置" error="customHeaders">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="customHeaders" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
非必填,自定义请求头是JSON字符串格式,如:{"token": "..."}
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="自定义FORM参数设置" error="customParams">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="customParams" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
非必填,自定义FORM参数是JSON字符串格式,如:{"param1": "..."}
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
<form-entry label="响应图片URL参数" error="resultUrlParam">
|
||||||
|
<input slot="field" class="textfield" type="text" v-model.trim="resultUrlParam" @keydown.enter="resolve()">
|
||||||
|
<div class="form-entry__info">
|
||||||
|
响应JSON中图片URL的路径,如 data.url
|
||||||
|
</div>
|
||||||
|
</form-entry>
|
||||||
|
</div>
|
||||||
|
<div class="modal__button-bar">
|
||||||
|
<button class="button" @click="config.reject()">取消</button>
|
||||||
|
<button class="button button--resolve" @click="resolve()">确认</button>
|
||||||
|
</div>
|
||||||
|
</modal-inner>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import modalTemplate from '../common/modalTemplate';
|
||||||
|
|
||||||
|
export default modalTemplate({
|
||||||
|
computedLocalSettings: {
|
||||||
|
name: 'name',
|
||||||
|
uploadUrl: 'uploadUrl',
|
||||||
|
fileParamName: 'fileParamName',
|
||||||
|
customHeaders: 'customHeaders',
|
||||||
|
customParams: 'customParams',
|
||||||
|
resultUrlParam: 'resultUrlParam',
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
resolve() {
|
||||||
|
if (!this.name) {
|
||||||
|
this.setError('name');
|
||||||
|
}
|
||||||
|
if (!this.uploadUrl) {
|
||||||
|
this.setError('uploadUrl');
|
||||||
|
}
|
||||||
|
if (!this.fileParamName) {
|
||||||
|
this.setError('fileParamName');
|
||||||
|
}
|
||||||
|
if (!this.resultUrlParam) {
|
||||||
|
this.setError('resultUrlParam');
|
||||||
|
}
|
||||||
|
let customHeaders = null;
|
||||||
|
if (this.customHeaders) {
|
||||||
|
try {
|
||||||
|
customHeaders = JSON.parse(this.customHeaders);
|
||||||
|
} catch (err) {
|
||||||
|
this.setError('customHeaders');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let customParams = null;
|
||||||
|
if (this.customParams) {
|
||||||
|
try {
|
||||||
|
customParams = JSON.parse(this.customParams);
|
||||||
|
} catch (err) {
|
||||||
|
this.setError('customParams');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.uploadUrl && this.fileParamName) {
|
||||||
|
this.config.resolve({
|
||||||
|
name: this.name,
|
||||||
|
uploadUrl: this.uploadUrl,
|
||||||
|
fileParamName: this.fileParamName,
|
||||||
|
resultUrlParam: this.resultUrlParam,
|
||||||
|
customHeaders,
|
||||||
|
customParams,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -264,6 +264,11 @@ export default [
|
|||||||
'SM.MS账号',
|
'SM.MS账号',
|
||||||
'将您的SM.MS账号链接到StackEdit中文版。',
|
'将您的SM.MS账号链接到StackEdit中文版。',
|
||||||
),
|
),
|
||||||
|
new Feature(
|
||||||
|
'addCustomAccount',
|
||||||
|
'自定义图床账号',
|
||||||
|
'将您的自定义图床账号链接到StackEdit中文版。',
|
||||||
|
),
|
||||||
new Feature(
|
new Feature(
|
||||||
'removeAccount',
|
'removeAccount',
|
||||||
'移除账号',
|
'移除账号',
|
||||||
|
@ -102,4 +102,8 @@ export default {
|
|||||||
.icon-provider--smms {
|
.icon-provider--smms {
|
||||||
background-image: url(../assets/iconSmms.svg);
|
background-image: url(../assets/iconSmms.svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-provider--custom {
|
||||||
|
background-image: url(../assets/iconCustom.svg);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
69
src/services/providers/helpers/customHelper.js
Normal file
69
src/services/providers/helpers/customHelper.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import md5 from 'js-md5';
|
||||||
|
import networkSvc from '../../networkSvc';
|
||||||
|
import store from '../../../store';
|
||||||
|
import userSvc from '../../userSvc';
|
||||||
|
import badgeSvc from '../../badgeSvc';
|
||||||
|
import utils from '../../utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义账号前缀
|
||||||
|
*/
|
||||||
|
const subPrefix = 'cs';
|
||||||
|
export default {
|
||||||
|
subPrefix,
|
||||||
|
async addAccount({
|
||||||
|
name,
|
||||||
|
uploadUrl,
|
||||||
|
fileParamName,
|
||||||
|
customHeaders,
|
||||||
|
customParams,
|
||||||
|
resultUrlParam,
|
||||||
|
}) {
|
||||||
|
userSvc.addUserInfo({
|
||||||
|
id: `${subPrefix}:${utils.encodeBase64(name)}`,
|
||||||
|
name,
|
||||||
|
imageUrl: '',
|
||||||
|
});
|
||||||
|
// Build token object including sub
|
||||||
|
const token = {
|
||||||
|
uploadUrl,
|
||||||
|
fileParamName,
|
||||||
|
customHeaders,
|
||||||
|
customParams,
|
||||||
|
resultUrlParam,
|
||||||
|
name,
|
||||||
|
sub: utils.encodeBase64(name),
|
||||||
|
};
|
||||||
|
// Add token to smms tokens
|
||||||
|
store.dispatch('data/addCustomToken', token);
|
||||||
|
badgeSvc.addBadge('addCustomAccount');
|
||||||
|
return token;
|
||||||
|
},
|
||||||
|
async uploadFile({
|
||||||
|
token,
|
||||||
|
file,
|
||||||
|
}) {
|
||||||
|
const newFileName = `${md5(await utils.encodeFiletoBase64(file))}.${file.type.split('/')[1]}`;
|
||||||
|
const newfile = new File([file], newFileName, { type: file.type });
|
||||||
|
const headers = token.customHeaders || {};
|
||||||
|
const formData = token.formData || {};
|
||||||
|
formData[token.fileParamName] = newfile;
|
||||||
|
const { body } = await networkSvc.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: token.uploadUrl,
|
||||||
|
headers,
|
||||||
|
formData,
|
||||||
|
});
|
||||||
|
const paramArray = token.resultUrlParam.split('.');
|
||||||
|
let result = body;
|
||||||
|
paramArray.forEach((paramName) => {
|
||||||
|
result = result[paramName];
|
||||||
|
if (!result) {
|
||||||
|
store.dispatch('notification/error', `自定义图床上传图片失败,响应Body为:${JSON.stringify(body)}`);
|
||||||
|
throw new Error(`自定义图床上传图片失败,响应Body为:${JSON.stringify(body)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
@ -217,6 +217,7 @@ export default {
|
|||||||
wordpressTokensBySub: (state, { tokensByType }) => tokensByType.wordpress || {},
|
wordpressTokensBySub: (state, { tokensByType }) => tokensByType.wordpress || {},
|
||||||
zendeskTokensBySub: (state, { tokensByType }) => tokensByType.zendesk || {},
|
zendeskTokensBySub: (state, { tokensByType }) => tokensByType.zendesk || {},
|
||||||
smmsTokensBySub: (state, { tokensByType }) => tokensByType.smms || {},
|
smmsTokensBySub: (state, { tokensByType }) => tokensByType.smms || {},
|
||||||
|
customTokensBySub: (state, { tokensByType }) => tokensByType.custom || {},
|
||||||
badgeCreations: getter('badgeCreations'),
|
badgeCreations: getter('badgeCreations'),
|
||||||
badgeTree: (state, { badgeCreations }) => features
|
badgeTree: (state, { badgeCreations }) => features
|
||||||
.map(feature => feature.toBadge(badgeCreations)),
|
.map(feature => feature.toBadge(badgeCreations)),
|
||||||
@ -313,5 +314,6 @@ export default {
|
|||||||
addZendeskToken: tokenAdder('zendesk'),
|
addZendeskToken: tokenAdder('zendesk'),
|
||||||
patchBadgeCreations: patcher('badgeCreations'),
|
patchBadgeCreations: patcher('badgeCreations'),
|
||||||
addSmmsToken: tokenAdder('smms'),
|
addSmmsToken: tokenAdder('smms'),
|
||||||
|
addCustomToken: tokenAdder('custom'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -134,7 +134,10 @@ const store = new Vuex.Store({
|
|||||||
hash: undefined,
|
hash: undefined,
|
||||||
}), true);
|
}), true);
|
||||||
const extension = item.type === 'syncLocation' ? 'sync' : 'publish';
|
const extension = item.type === 'syncLocation' ? 'sync' : 'publish';
|
||||||
result[id] = `${pathsByItemId[item.fileId]}.${encodedItem}.${extension}`;
|
const path = pathsByItemId[item.fileId];
|
||||||
|
if (path) {
|
||||||
|
result[id] = `${path}.${encodedItem}.${extension}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
Loading…
Reference in New Issue
Block a user