update
parent
ab165c0002
commit
15e4a8062a
|
@ -14,11 +14,6 @@ __dir__ = os.path.dirname(os.path.realpath(__file__))
|
|||
|
||||
web_root = os.path.join(__dir__, './webapp')
|
||||
home_dir = os.getenv('HOME')
|
||||
config_dir = os.path.join(home_dir, '.config/dooke')
|
||||
|
||||
|
||||
if not os.path.isdir(config_dir):
|
||||
os.mkdir(config_dir)
|
||||
|
||||
|
||||
class Application(Gtk.Application):
|
||||
|
|
|
@ -6,10 +6,21 @@
|
|||
|
||||
import 'es.shim'
|
||||
import { html, css, Component } from 'wkit'
|
||||
import { createApp, createRouter } from 'wkitd'
|
||||
import { createApp } from 'wkitd'
|
||||
|
||||
import 'ui/icon/index.js'
|
||||
import 'ui/scroll/index.js'
|
||||
import 'ui/layer/index.js'
|
||||
import 'ui/space/index.js'
|
||||
import 'ui/form/input.js'
|
||||
import 'ui/form/switch.js'
|
||||
import 'ui/form/button.js'
|
||||
import 'ui/form/link.js'
|
||||
|
||||
import router from './router.js'
|
||||
import store from './store.js'
|
||||
import './components/home.js'
|
||||
|
||||
import '../components/sidebar.js'
|
||||
|
||||
import { noop } from './utils/index.js'
|
||||
|
||||
|
@ -26,6 +37,11 @@ createApp({
|
|||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
router-view {
|
||||
flex: 1;
|
||||
height: 100;
|
||||
}
|
||||
`
|
||||
],
|
||||
methods: {
|
||||
|
@ -34,8 +50,18 @@ createApp({
|
|||
}
|
||||
},
|
||||
render() {
|
||||
return html` <wc-home @contextmenu.prevent=${noop}></wc-home> `
|
||||
return html`
|
||||
<wc-sidebar></wc-sidebar>
|
||||
<router-view></router-view>
|
||||
<wc-layer ref="context" left="100px" top="0" radius="0">
|
||||
<ul class="context-menu" @click=${this.confirmAction}>
|
||||
<li class="item" data-act="del">删除域名</li>
|
||||
<li class="item" data-act="edit">修改域名</li>
|
||||
</ul>
|
||||
</wc-layer>
|
||||
`
|
||||
}
|
||||
})
|
||||
.use(router)
|
||||
.use(store)
|
||||
.mount()
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2023/08/08 18:19:17
|
||||
*/
|
||||
import { html, css, Component, classMap, nextTick, outsideClick } from 'wkit'
|
||||
|
||||
import 'ui/icon/index.js'
|
||||
import 'ui/scroll/index.js'
|
||||
import 'ui/layer/index.js'
|
||||
import 'ui/space/index.js'
|
||||
import 'ui/form/input.js'
|
||||
import 'ui/form/switch.js'
|
||||
import 'ui/form/button.js'
|
||||
import 'ui/form/link.js'
|
||||
|
||||
import './sidebar.js'
|
||||
import './permission.js'
|
||||
import './records.js'
|
||||
|
||||
import { checkPermission, getHistory, saveHosts, noop } from '../utils/index.js'
|
||||
|
||||
const HOST_DATA = await getHistory()
|
||||
|
||||
class Home extends Component {
|
||||
static props = {
|
||||
editDomain: '', // 当前临时要编辑的域名, 即右键菜单选择到的
|
||||
permissionShow: false
|
||||
}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
:host {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 32px;
|
||||
color: var(--color-dark-1);
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.noselect {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
`,
|
||||
|
||||
css`
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.main .toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
padding: 0 15px;
|
||||
border-bottom: 1px solid var(--color-plain-3);
|
||||
background: var(--color-plain-1);
|
||||
}
|
||||
.main .list {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
`,
|
||||
|
||||
css`
|
||||
.context-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100px;
|
||||
padding: 5px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.context-menu .item {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.context-menu .item :hover {
|
||||
background: #f2f5fc;
|
||||
}
|
||||
`
|
||||
]
|
||||
|
||||
async mounted() {
|
||||
let writable = await checkPermission()
|
||||
|
||||
if (writable) {
|
||||
this.$store.HOST_DATA = HOST_DATA
|
||||
this.$store.domains = Object.keys(HOST_DATA)
|
||||
this.$refs.domain.mounted()
|
||||
outsideClick(this.$refs.context, _ => this.$refs.context.close())
|
||||
} else {
|
||||
this.permissionShow = true
|
||||
}
|
||||
}
|
||||
|
||||
addRecord() {
|
||||
if (this.$store.activeDomain) {
|
||||
this.$store.records.push({
|
||||
record: '',
|
||||
value: '',
|
||||
enabled: true,
|
||||
remark: ''
|
||||
})
|
||||
nextTick(_ => (this.$refs.list.scrollTop = 1e6))
|
||||
} else {
|
||||
layer.toast('请先选择域名', 'warn')
|
||||
}
|
||||
}
|
||||
|
||||
showMenu(ev) {
|
||||
this.$refs.context.close()
|
||||
var { pageX, pageY } = ev
|
||||
if (pageY + 70 > 600) {
|
||||
pageY -= 70
|
||||
}
|
||||
|
||||
var elem = ev.target
|
||||
|
||||
if (elem.tagName !== 'LI') {
|
||||
elem = elem.parentNode
|
||||
}
|
||||
this.editDomain = elem.dataset.name
|
||||
setTimeout(_ => {
|
||||
this.$refs.context.moveTo({ left: pageX + 'px', top: pageY + 'px' })
|
||||
this.$refs.context.show()
|
||||
})
|
||||
}
|
||||
|
||||
confirmAction(ev) {
|
||||
this.$refs.context.close()
|
||||
if (ev.target.tagName === 'LI') {
|
||||
let act = ev.target.dataset.act
|
||||
let { HOST_DATA, records, domains } = this.$store
|
||||
let idx = domains.indexOf(this.editDomain)
|
||||
|
||||
if (act === 'del') {
|
||||
layer
|
||||
.confirm(`是否要删除域名「${this.editDomain}」?`)
|
||||
.then(res => {
|
||||
if (this.editDomain === this.$store.activeDomain) {
|
||||
if (records.length) {
|
||||
return layer.toast(
|
||||
'该域名下有主机记录, 请先删除主机记录后再删除域名',
|
||||
'error'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (HOST_DATA[this.editDomain].length > 0) {
|
||||
return layer.toast(
|
||||
'该域名下有主机记录, 请先删除主机记录后再删除域名',
|
||||
'error'
|
||||
)
|
||||
}
|
||||
}
|
||||
delete HOST_DATA[this.editDomain]
|
||||
|
||||
domains.splice(idx, 1)
|
||||
|
||||
this.editDomain = ''
|
||||
this.$store.records = []
|
||||
this.$store.activeDomain = domains[0]
|
||||
this.$refs.domain.mounted()
|
||||
this.save()
|
||||
})
|
||||
.catch(noop)
|
||||
} else if (act === 'edit') {
|
||||
layer
|
||||
.prompt(
|
||||
`请输入新的名字「${this.editDomain}」`,
|
||||
this.editDomain,
|
||||
(val, done) => {
|
||||
if (val === this.editDomain || HOST_DATA[val]) {
|
||||
return layer.toast(`${val} 域名没有变化, 或已经存在`)
|
||||
}
|
||||
|
||||
if (
|
||||
val === 'localhost' ||
|
||||
val === 'local' ||
|
||||
/^[\w.]+\.[a-z]+$/.test(val)
|
||||
) {
|
||||
done()
|
||||
} else {
|
||||
layer.toast('域名格式错误', 'error')
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(val => {
|
||||
domains[idx] = val
|
||||
HOST_DATA[val] = HOST_DATA[this.editDomain]
|
||||
delete HOST_DATA[this.editDomain]
|
||||
|
||||
this.$store.activeDomain = val
|
||||
this.editDomain = ''
|
||||
this.$refs.domain.mounted()
|
||||
this.save()
|
||||
})
|
||||
.catch(noop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
let { HOST_DATA, activeDomain, records } = this.$store
|
||||
if (activeDomain) {
|
||||
HOST_DATA[activeDomain] = records.filter(it => it.record && it.value)
|
||||
}
|
||||
saveHosts(HOST_DATA)
|
||||
layer.toast('保存成功', 'success')
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<wc-sidebar
|
||||
ref="domain"
|
||||
@toggle-domain=${_ => (this.$refs.list.scrollTop = 0)}
|
||||
@show-menu=${ev => this.showMenu(ev.event)}
|
||||
@save=${this.save}
|
||||
></wc-sidebar>
|
||||
|
||||
<main class="main noselect">
|
||||
<header class="toolbar">
|
||||
<wc-button size="m" icon="plus" @click=${this.addRecord}
|
||||
>新增记录</wc-button
|
||||
>
|
||||
<wc-button size="m" icon="fly" @click=${this.save}>保存</wc-button>
|
||||
</header>
|
||||
|
||||
<wc-records class="list" ref="list"></wc-records>
|
||||
</main>
|
||||
|
||||
<wc-permission
|
||||
class=${classMap({ visible: this.permissionShow })}
|
||||
></wc-permission>
|
||||
|
||||
<wc-layer ref="context" left="100px" top="0" radius="0">
|
||||
<ul class="context-menu" @click=${this.confirmAction}>
|
||||
<li class="item" data-act="del">删除域名</li>
|
||||
<li class="item" data-act="edit">修改域名</li>
|
||||
</ul>
|
||||
</wc-layer>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
Home.reg('home')
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2023/08/08 18:19:17
|
||||
*/
|
||||
import { html, css, Component } from 'wkit'
|
||||
|
||||
import { checkPermission } from '../utils/index.js'
|
||||
|
||||
const tips_header = `/************************************************************/
|
||||
* hosts文件没有写权限 *
|
||||
/************************************************************/
|
||||
`
|
||||
|
||||
class Permission extends Component {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
.noselect {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.permission-error {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1024;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 24px 52px;
|
||||
line-height: 1.5;
|
||||
background: rgba(255, 233, 233, 0.95);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 14px;
|
||||
color: var(--color-red-1);
|
||||
}
|
||||
|
||||
fieldset {
|
||||
width: 600px;
|
||||
padding: 0 30px 30px;
|
||||
border: 1px solid var(--color-orange-1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
legend {
|
||||
padding: 0 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin-top: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
code {
|
||||
display: block;
|
||||
padding: 8px 10px;
|
||||
margin-top: 8px;
|
||||
border-left: 3px solid var(--color-plain-3);
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
`
|
||||
|
||||
async check() {
|
||||
let writable = await checkPermission()
|
||||
if (writable) {
|
||||
location.reload()
|
||||
} else {
|
||||
layer.toast('hosts文件没有写权限, 请按提示修改', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="permission-error">
|
||||
<pre class="noselect">${tips_header}</pre>
|
||||
<fieldset>
|
||||
<legend>操作指引</legend>
|
||||
<dl>
|
||||
<dt>MacOS用户</dt>
|
||||
<dd>打开终端, 执行以下命令</dd>
|
||||
<dd><code>sudo chown $USER:admin /etc/hosts</code></dd>
|
||||
|
||||
<dt>Linux用户</dt>
|
||||
<dd>打开终端, 执行以下命令</dd>
|
||||
<dd><code>sudo chown $USER: /etc/hosts</code></dd>
|
||||
|
||||
<dt>完成之后</dt>
|
||||
<dd>点击下面的按钮重新检测.</dd>
|
||||
<dd>
|
||||
<wc-button type="danger" @click=${this.check}>权限检测</wc-button>
|
||||
</dd>
|
||||
</dl>
|
||||
</fieldset>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
Permission.reg('permission')
|
|
@ -15,7 +15,7 @@ class Sidebar extends Component {
|
|||
flex-direction: column;
|
||||
width: 180px;
|
||||
height: 100vh;
|
||||
background: var(--color-plain-2);
|
||||
background: var(--color-plain-1);
|
||||
}
|
||||
.noselect {
|
||||
-webkit-touch-callout: none;
|
||||
|
@ -23,26 +23,28 @@ class Sidebar extends Component {
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.domain-list {
|
||||
.navibar {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.domain-list .item {
|
||||
.navibar .item {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
gap: 12px;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.item wc-icon {
|
||||
--wc-icon-size: 12px;
|
||||
margin-left: 8px;
|
||||
color: var(--color-grey-2);
|
||||
--wc-icon-size: 16px;
|
||||
}
|
||||
|
||||
.item:hover,
|
||||
|
@ -50,114 +52,43 @@ class Sidebar extends Component {
|
|||
background: #fff;
|
||||
}
|
||||
.item.active {
|
||||
border-right: 2px solid var(--color-orange-1);
|
||||
color: var(--color-orange-1);
|
||||
}
|
||||
.item.active wc-icon {
|
||||
color: var(--color-orange-1);
|
||||
}
|
||||
.item.blank {
|
||||
justify-content: center;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.item.blank:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.action {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
padding: 0 10px;
|
||||
color: var(--color-orange-3);
|
||||
box-shadow: 0 0 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
`
|
||||
|
||||
addDomain() {
|
||||
layer
|
||||
.prompt('请输入根域名', function (val, done) {
|
||||
if (
|
||||
val === 'localhost' ||
|
||||
val === 'local' ||
|
||||
/^[\w.\-]+\.[a-z]+$/.test(val)
|
||||
) {
|
||||
done()
|
||||
} else {
|
||||
layer.toast('域名格式错误', 'error')
|
||||
}
|
||||
})
|
||||
.then(val => {
|
||||
let { HOST_DATA, records } = this.$store
|
||||
this.$store.domains.push(val)
|
||||
HOST_DATA[val] = []
|
||||
if (!this.$store.activeDomain) {
|
||||
this.toggleDomain(null, val)
|
||||
}
|
||||
this.$emit('save')
|
||||
})
|
||||
.catch(noop)
|
||||
}
|
||||
|
||||
toggleDomain(ev, name) {
|
||||
let { HOST_DATA, records } = this.$store
|
||||
name = name ?? ev.currentTarget.dataset.name
|
||||
this.$store.activeDomain = name
|
||||
|
||||
this.$store.records = records = (HOST_DATA[name] || []).sort((a, b) =>
|
||||
a.record.localeCompare(b.record)
|
||||
)
|
||||
|
||||
let tmp_records = Object.create(null)
|
||||
for (let it of records) {
|
||||
if (tmp_records[it.record]) {
|
||||
tmp_records[it.record].push(it)
|
||||
} else {
|
||||
tmp_records[it.record] = [it]
|
||||
}
|
||||
switchNavi(id) {
|
||||
let path = '/' + id
|
||||
this.$store.navi = id
|
||||
if (id === 'containers') {
|
||||
path = '/'
|
||||
}
|
||||
this.$store.tmp_records = tmp_records
|
||||
|
||||
document.title = `伪域名解析 ${name} `
|
||||
localStorage.setItem('last_domain', name)
|
||||
nextTick(() => {
|
||||
this.$emit('toggle-domain')
|
||||
})
|
||||
this.$router.push(path)
|
||||
localStorage.setItem('last_navi', id)
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.toggleDomain(null, this.$store.activeDomain)
|
||||
this.switchNavi(this.$store.navi)
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<wc-scroll class="domain-list noselect">
|
||||
<ul
|
||||
@contextmenu.prevent=${ev => this.$emit('show-menu', { event: ev })}
|
||||
>
|
||||
${this.$store.domains.map(
|
||||
it => html`
|
||||
<li
|
||||
class=${classMap({
|
||||
item: true,
|
||||
active: it === this.$store.activeDomain
|
||||
})}
|
||||
data-name=${it}
|
||||
@click=${this.toggleDomain}
|
||||
>
|
||||
<span>${it}</span>
|
||||
<wc-icon name="right"></wc-icon>
|
||||
</li>
|
||||
`
|
||||
)}
|
||||
${this.$store.domains.length < 1
|
||||
? html`<li class="item blank">没有域名</li>`
|
||||
: ''}
|
||||
</ul>
|
||||
</wc-scroll>
|
||||
<section class="action">
|
||||
<wc-button circle icon="plus" @click=${this.addDomain}> </wc-button>
|
||||
</section>
|
||||
<menu class="navibar">
|
||||
${this.$store.menus.map(
|
||||
it => html`
|
||||
<li
|
||||
class=${classMap({
|
||||
item: true,
|
||||
active: it.id === this.$store.navi
|
||||
})}
|
||||
@click=${ev => this.switchNavi(it.id)}
|
||||
>
|
||||
<wc-icon name=${it.icon}></wc-icon>
|
||||
<span>${it.name}</span>
|
||||
</li>
|
||||
`
|
||||
)}
|
||||
</menu>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2024/01/11 17:42:40
|
||||
*/
|
||||
|
||||
import { createRouter, createWebHistory } from 'wkitd'
|
||||
|
||||
import './views/home.js'
|
||||
import './views/images.js'
|
||||
import './views/volumes.js'
|
||||
|
||||
export default createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'wc-containers'
|
||||
},
|
||||
{
|
||||
path: '/images',
|
||||
name: 'wc-images'
|
||||
},
|
||||
{
|
||||
path: '/volumes',
|
||||
name: 'wc-volumes'
|
||||
}
|
||||
]
|
||||
})
|
|
@ -7,9 +7,22 @@
|
|||
import { createStore } from 'wkitd'
|
||||
|
||||
export default createStore({
|
||||
HOST_DATA: {},
|
||||
activeDomain: localStorage.getItem('last_domain') || '', //当前选中的域名
|
||||
domains: [],
|
||||
records: [],
|
||||
tmp_records: []
|
||||
navi: localStorage.getItem('last_navi') || 'containers',
|
||||
menus: [
|
||||
{
|
||||
id: 'containers',
|
||||
name: '容器管理',
|
||||
icon: 'layout'
|
||||
},
|
||||
{
|
||||
id: 'images',
|
||||
name: '镜像管理',
|
||||
icon: 'menu'
|
||||
},
|
||||
{
|
||||
id: 'volumes',
|
||||
name: '磁盘管理',
|
||||
icon: 'pie'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
|
|
@ -6,95 +6,10 @@
|
|||
|
||||
import { nextTick } from 'wkit'
|
||||
|
||||
const APP_CONFIG_DIR = `${native.env.CONFIG_DIR}/hosts-switch`
|
||||
const HOST_FILE = `${APP_CONFIG_DIR}/host.cache`
|
||||
const LOCK_FILE = `${APP_CONFIG_DIR}/lock`
|
||||
|
||||
export function noop() {}
|
||||
|
||||
export function checkPermission() {
|
||||
return native.fs.access('/etc/hosts', 'a+')
|
||||
}
|
||||
export function checkPermission() {}
|
||||
|
||||
export async function getHistory() {
|
||||
if (await native.fs.isfile(LOCK_FILE)) {
|
||||
let cache = await native.fs.read(HOST_FILE)
|
||||
return JSON.parse(cache)
|
||||
}
|
||||
export async function getHistory() {}
|
||||
|
||||
let cache = await native.fs.read('/etc/hosts')
|
||||
let records = cache.split(/[\n\r]+/)
|
||||
let list = []
|
||||
let dict = {}
|
||||
|
||||
records.forEach(str => {
|
||||
str = str.trim()
|
||||
let matches = str.match(/^(#*?)\s*(\d+\.\d+\.\d+\.\d+)\s+(.*)/)
|
||||
|
||||
if (matches) {
|
||||
let names = matches[3].split(/\s+/).map(it => it.trim())
|
||||
let name
|
||||
while ((name = names.pop())) {
|
||||
list.push({ ip: matches[2], enabled: !matches[1], name })
|
||||
}
|
||||
}
|
||||
})
|
||||
records = null
|
||||
|
||||
list.forEach(it => {
|
||||
it.name = it.name.split('.')
|
||||
let domain = it.name.splice(-2, 2).join('.')
|
||||
if (domain === 'com.cn' || domain === 'org.cn' || domain === 'net.cn') {
|
||||
domain = it.name.pop() + '.' + domain
|
||||
}
|
||||
|
||||
if (dict[domain]) {
|
||||
dict[domain].push({
|
||||
value: it.ip,
|
||||
enabled: it.enabled,
|
||||
record: it.name.join('.') || '@',
|
||||
remark: ''
|
||||
})
|
||||
} else {
|
||||
dict[domain] = [
|
||||
{
|
||||
value: it.ip,
|
||||
enabled: it.enabled,
|
||||
record: it.name.join('.') || '@',
|
||||
remark: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
list = null
|
||||
try {
|
||||
await native.fs.write(HOST_FILE, JSON.stringify(dict))
|
||||
await native.fs.write(LOCK_FILE, '')
|
||||
} catch (err) {}
|
||||
return dict
|
||||
}
|
||||
|
||||
export function saveHosts(dict) {
|
||||
nextTick(async () => {
|
||||
var txt = ''
|
||||
for (let k in dict) {
|
||||
for (let it of dict[k]) {
|
||||
if (it.enabled) {
|
||||
var name = it.record === '@' ? '' : it.record
|
||||
if (name) {
|
||||
name += '.'
|
||||
}
|
||||
txt += `${it.value.padEnd(15, ' ')} ${name + k}\n`
|
||||
}
|
||||
}
|
||||
txt += '\n'
|
||||
}
|
||||
|
||||
try {
|
||||
await native.fs.write(HOST_FILE, JSON.stringify(dict))
|
||||
await native.fs.write('/etc/hosts', txt)
|
||||
} catch (err) {
|
||||
layer.alert(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
export function saveHosts(dict) {}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* {}
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2023/08/08 18:19:17
|
||||
*/
|
||||
import { html, css, Component, classMap, nextTick, outsideClick } from 'wkit'
|
||||
|
||||
// import '../components/records.js'
|
||||
|
||||
import { noop } from '../utils/index.js'
|
||||
|
||||
class Home extends Component {
|
||||
static props = {}
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: var(--color-dark-1);
|
||||
background: #fff;
|
||||
}
|
||||
.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.noselect {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
`,
|
||||
|
||||
css`
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
}
|
||||
.main .toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 48px;
|
||||
border-bottom: 1px solid var(--color-plain-3);
|
||||
}
|
||||
.main .list {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
`,
|
||||
|
||||
css`
|
||||
.context-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100px;
|
||||
padding: 5px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.context-menu .item {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.context-menu .item :hover {
|
||||
background: #f2f5fc;
|
||||
}
|
||||
`
|
||||
]
|
||||
|
||||
async mounted() {
|
||||
// outsideClick(this.$refs.context, _ => this.$refs.context.close())
|
||||
}
|
||||
|
||||
showMenu(ev) {
|
||||
this.$refs.context.close()
|
||||
var { pageX, pageY } = ev
|
||||
if (pageY + 70 > 600) {
|
||||
pageY -= 70
|
||||
}
|
||||
|
||||
var elem = ev.target
|
||||
|
||||
if (elem.tagName !== 'LI') {
|
||||
elem = elem.parentNode
|
||||
}
|
||||
this.editDomain = elem.dataset.name
|
||||
setTimeout(_ => {
|
||||
this.$refs.context.moveTo({ left: pageX + 'px', top: pageY + 'px' })
|
||||
this.$refs.context.show()
|
||||
})
|
||||
}
|
||||
|
||||
confirmAction(ev) {
|
||||
this.$refs.context.close()
|
||||
if (ev.target.tagName === 'LI') {
|
||||
let act = ev.target.dataset.act
|
||||
if (act === 'del') {
|
||||
} else if (act === 'edit') {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
let { HOST_DATA, activeDomain, records } = this.$store
|
||||
if (activeDomain) {
|
||||
HOST_DATA[activeDomain] = records.filter(it => it.record && it.value)
|
||||
}
|
||||
saveHosts(HOST_DATA)
|
||||
layer.toast('保存成功', 'success')
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<main class="main noselect">
|
||||
<header class="toolbar">
|
||||
<wc-input round></wc-input>
|
||||
</header>
|
||||
</main>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
Home.reg('containers')
|
Loading…
Reference in New Issue