ui #39
This commit is contained in:
@@ -22,6 +22,17 @@ export function not_nam(
|
||||
return !is_nam(nam)
|
||||
}
|
||||
|
||||
export function is_nbr(
|
||||
nbr?: null | string
|
||||
): nbr is string {
|
||||
return typeof nbr === "string" && /^1\d{10}$/.test(nbr)
|
||||
}
|
||||
export function not_nbr(
|
||||
nbr?: null | string
|
||||
) {
|
||||
return !is_nbr(nbr)
|
||||
}
|
||||
|
||||
export function is_intro(
|
||||
intro?: null | Id["intro"]
|
||||
) {
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { Usr } from "./typ.ts"
|
||||
import { coll, DocC, DocD, DocR, DocU, Update } from "../db.ts"
|
||||
import { is_nbr, not_nbr } from "../ont/sms.ts"
|
||||
import { not_adm } from "../ont/adm.ts"
|
||||
import { is_id, not_id, not_nam, not_intro } from "./is.ts"
|
||||
import { is_id, not_id, not_nam, is_nbr, not_nbr, not_intro } from "./is.ts"
|
||||
|
||||
export async function usr_c(
|
||||
nbr: NonNullable<Usr["nbr"]>,
|
||||
|
@@ -2,17 +2,6 @@ import { to_hex } from "./base.ts"
|
||||
import { digest, key, sign } from "./crypt.ts"
|
||||
import { utc_date } from "./utc.ts"
|
||||
|
||||
export function is_nbr(
|
||||
nbr?: null | string
|
||||
): nbr is string {
|
||||
return typeof nbr === "string" && /^1\d{10}$/.test(nbr)
|
||||
}
|
||||
export function not_nbr(
|
||||
nbr?: null | string
|
||||
) {
|
||||
return !is_nbr(nbr)
|
||||
}
|
||||
|
||||
const tc: {
|
||||
id: string,
|
||||
key: string,
|
||||
|
@@ -4,7 +4,7 @@ import { act_c, act_d, act_r, act_u } from "../src/eid/act.ts"
|
||||
import { agd_c, agd_d, agd_r, agd_u } from "../src/eid/agd.ts"
|
||||
import { aut_c, aut_d, aut_r, aut_u } from "../src/eid/aut.ts"
|
||||
import { id, idnam, nid_of_adm } from "../src/eid/id.ts"
|
||||
import { is_id, is_intro, is_nam, not_id, not_intro, not_nam, is_rol, not_rol } from "../src/eid/is.ts"
|
||||
import { is_id, is_intro, is_nam, not_id, not_intro, not_nam, is_rol, not_rol, is_nbr, not_nbr } from "../src/eid/is.ts"
|
||||
import { nrec, rec_c, rec_d, rec_r, rec_u, rol } from "../src/eid/rec.ts"
|
||||
import { soc_c, soc_d, sidnam, soc_r, soc_u } from "../src/eid/soc.ts"
|
||||
import { usr_c, usr_r, usr_u, usr_d } from "../src/eid/usr.ts"
|
||||
@@ -46,6 +46,11 @@ Deno.test("id", async () => {
|
||||
await Promise.all(sid.map(soc_d))
|
||||
})
|
||||
|
||||
Deno.test("nbr", () => {
|
||||
assert(is_nbr("11111111111"))
|
||||
assert(not_nbr(undefined) && not_nbr(null) && not_nbr("") && not_nbr("123"))
|
||||
})
|
||||
|
||||
Deno.test("usr", async () => {
|
||||
const nbr = "11111111114"
|
||||
assert(null === await usr_r({ _id: 1 }, { nbr: 1 }))
|
||||
|
@@ -3,7 +3,6 @@ import { is_adm, is_adm1, is_adm2, not_adm, not_adm1, not_adm2 } from "../src/on
|
||||
import { from_base64, from_hex, from_u8, to_base64, to_hex, to_u8 } from "../src/ont/base.ts"
|
||||
import { digest } from "../src/ont/crypt.ts"
|
||||
import { jwk_load, jwk_set, jwt_sign, jwt_verify } from "../src/ont/jwt.ts"
|
||||
import { is_nbr, not_nbr } from "../src/ont/sms.ts"
|
||||
import { utc_date, utc_h, utc_medium, utc_short } from "../src/ont/utc.ts"
|
||||
|
||||
Deno.test("base", () => {
|
||||
@@ -39,11 +38,6 @@ Deno.test("adm", () => {
|
||||
assert(not_adm2(undefined) && not_adm2(null) && not_adm2("") && not_adm2("四川"))
|
||||
})
|
||||
|
||||
Deno.test("nbr", () => {
|
||||
assert(is_nbr("11111111111"))
|
||||
assert(not_nbr(undefined) && not_nbr(null) && not_nbr("") && not_nbr("123"))
|
||||
})
|
||||
|
||||
Deno.test("dig", async () => {
|
||||
const h = `${Math.floor(Date.now() % utc_h * Math.random())}`
|
||||
const h1000 = await digest(h, 1000)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,19 @@
|
||||
import type { Id } from "../../src/eid/typ.ts"
|
||||
import type { Aut, Id } from "../../src/eid/typ.ts"
|
||||
import type { Pas } from "../../src/pra/pas.ts"
|
||||
import type { Usr, Soc } from "../../src/pra/que.ts"
|
||||
import { utc_medium } from "../../src/ont/utc.ts"
|
||||
import { adm } from "../../src/ont/adm.ts"
|
||||
import { Template } from "./template.ts"
|
||||
import { pos, Template, utc_refresh } from "./template.ts"
|
||||
import { is_aut } from "../../src/pra/con.ts"
|
||||
import { Usr, Soc, hash } from "./article.ts"
|
||||
import type { DocU } from "../../src/db.ts"
|
||||
|
||||
export function label(
|
||||
el: HTMLElement,
|
||||
s: string,
|
||||
) {
|
||||
const l = el.previousElementSibling as HTMLLabelElement
|
||||
l.innerText = s
|
||||
}
|
||||
|
||||
function selopt(
|
||||
sel: HTMLSelectElement,
|
||||
@@ -30,63 +39,83 @@ export function admsel(
|
||||
t.adm1.addEventListener("change", () => selopt(t.adm2, adm.get(t.adm1.value)!))
|
||||
}
|
||||
|
||||
export function idanchor(
|
||||
id: number[],
|
||||
idnam: Map<Id["_id"], Id["nam"]>,
|
||||
el: HTMLElement,
|
||||
export function ida(
|
||||
t: HTMLElement,
|
||||
pf: "" | "s" | "a",
|
||||
nam: Map<Id["_id"], Id["nam"]>,
|
||||
id?: number[],
|
||||
) {
|
||||
if (id.length === 0) { el.innerText = "无"; return }
|
||||
if (!id) id = [...nam.keys()]
|
||||
if (id.length === 0) return
|
||||
id.forEach(id => {
|
||||
const a = el.appendChild(document.createElement("a"))
|
||||
const a = t.appendChild(document.createElement("a"))
|
||||
a.href = `#${pf}${id}`
|
||||
a.innerText = idnam.get(id) ?? `${id}`
|
||||
a.innerText = nam.get(id) ?? `${pf}${id}`
|
||||
})
|
||||
}
|
||||
|
||||
function idmeta(
|
||||
export function idmeta(
|
||||
pas: Pas | null,
|
||||
id: Omit<NonNullable<Usr | Soc>, "unam"> & { unam: Map<Id["_id"], Id["nam"]> },
|
||||
t: Template["usr" | "soc"],
|
||||
id: Usr | Soc,
|
||||
): boolean {
|
||||
let pro: null | "rej" | "ref" = null
|
||||
if (id.rej.length >= 2) pro = "rej"
|
||||
else if (id.ref.length < 2) pro = "ref"
|
||||
const pub: boolean = pro === null || (pas !== null && is_aut(pas.aut, "pro_usr"))
|
||||
|
||||
if (pro === "rej") {
|
||||
t.id.classList.add("red")
|
||||
t.proc.classList.add("red")
|
||||
} else if (pro === "ref") {
|
||||
t.id.classList.add("green")
|
||||
t.proc.classList.add("green")
|
||||
} else t.proc.classList.add("gray")
|
||||
const [rej, ref] = [id.rej.length >= 2, id.ref.length < 2]
|
||||
const re: "rej" | "ref" | null = rej ? "rej" : ref ? "ref" : null
|
||||
const { aut }: { aut?: Aut["aut"][0] } = {
|
||||
...t.tid === "usr" ? { aut: "pre_usr" } : {},
|
||||
...t.tid === "soc" ? { aut: "pre_soc" } : {},
|
||||
}
|
||||
const pub: boolean = re === null || (pas !== null && aut !== undefined && is_aut(pas.aut, aut))
|
||||
|
||||
t.adm.innerText = `${id.adm1} ${id.adm2}`
|
||||
t.utc.innerText = `${utc_medium(id.utc)}`
|
||||
idanchor(id.rej, id.unam, t.rej, "")
|
||||
idanchor(id.ref, id.unam, t.ref, "")
|
||||
ida(t.rej, "", id.unam, id.rej)
|
||||
ida(t.ref, "", id.unam, id.ref)
|
||||
|
||||
if (id.rej.length >= 2) {
|
||||
t.rej.classList.add("red")
|
||||
t.rejc.classList.add("red")
|
||||
} else t.rejc.classList.add("gray")
|
||||
if (id.ref.length < 2) {
|
||||
t.ref.classList.add("green")
|
||||
t.refc.classList.add("green")
|
||||
} else t.refc.classList.add("gray")
|
||||
if (rej) [t.rej, t.rejc].forEach(el => el.classList.add("red"))
|
||||
if (ref) [t.ref, t.refc].forEach(el => el.classList.add("green"))
|
||||
if (re === "rej") [t.id, t.proc].forEach(el => el.classList.add("red"))
|
||||
else if (re === "ref") [t.id, t.proc].forEach(el => el.classList.add("green"))
|
||||
|
||||
return pub
|
||||
}
|
||||
|
||||
export function id(
|
||||
pas: Pas | null,
|
||||
ph: "" | "s",
|
||||
id: Omit<NonNullable<Usr | Soc>, "unam"> & { unam: Map<Id["_id"], Id["nam"]> },
|
||||
t: Template["usr" | "soc"],
|
||||
): boolean {
|
||||
t.idnam.href = `#${ph}${id._id}`
|
||||
t.id.innerText = `${ph}${id._id}`
|
||||
t.nam.innerText = id.nam
|
||||
return idmeta(pas, id, t) || ph === "" && pas !== null && pas.id.uid === id._id
|
||||
export function idnam(
|
||||
t: Template["usr" | "soc" | "pre"],
|
||||
id: string,
|
||||
nam?: string,
|
||||
) {
|
||||
t.idnam.href = `#${id}`
|
||||
t.id.innerText = id
|
||||
if (hash === id) t.id.classList.add("active")
|
||||
if (nam) t.nam.innerText = nam
|
||||
}
|
||||
|
||||
export function pro(
|
||||
pas: Pas,
|
||||
t: Template["usr" | "soc"],
|
||||
id: Usr | Soc,
|
||||
re?: (r: Id["_id"]) => void,
|
||||
) {
|
||||
const [prorej, proref] = [!id.rej.includes(pas.id.uid), !id.ref.includes(pas.id.uid)]
|
||||
t.prorej.innerText = prorej ? "反对" : "取消反对"
|
||||
t.proref.innerText = proref ? "推荐" : "取消推荐"
|
||||
if (re) {
|
||||
const pid = {
|
||||
...t.tid === "usr" ? { uid: id._id } : {},
|
||||
...t.tid === "soc" ? { sid: id._id } : {},
|
||||
}
|
||||
t.prorej.addEventListener("click", async () => {
|
||||
t.prorej.disabled = true
|
||||
const c = await pos<DocU>("pro", { re: "rej", ...pid, pro: prorej })
|
||||
if (c && c > 0) setTimeout(() => re(id._id), utc_refresh)
|
||||
else t.prorej.disabled = false
|
||||
})
|
||||
t.proref.addEventListener("click", async () => {
|
||||
t.proref.disabled = true
|
||||
const c = await pos<DocU>("pro", { re: "ref", ...pid, pro: proref })
|
||||
if (c && c > 0) setTimeout(() => re(id._id), utc_refresh)
|
||||
else t.proref.disabled = false
|
||||
})
|
||||
} else t.prorej.disabled = t.proref.disabled = true
|
||||
}
|
||||
|
@@ -1,14 +1,15 @@
|
||||
export async function que<T>(
|
||||
q: string
|
||||
) {
|
||||
const res = await fetch(`/q/${q}`)
|
||||
const etag = res.headers.get("etag")?.substring(3)
|
||||
const r = await fetch(`/q/${q}`)
|
||||
const etag = r.headers.get("etag")?.substring(3)
|
||||
if (etag) utc_etag = parseInt(etag)
|
||||
return res.json() as T
|
||||
return r.json() as T
|
||||
}
|
||||
|
||||
export async function pos<T>(
|
||||
f: string, b: Record<string, string | number | boolean>
|
||||
f: string,
|
||||
b: Record<string, string | number | boolean>,
|
||||
) {
|
||||
const res = await fetch(`/p/${f}`, {
|
||||
method: "POST",
|
||||
@@ -17,14 +18,16 @@ export async function pos<T>(
|
||||
return res.json() as T
|
||||
}
|
||||
|
||||
export const utc_refresh = 500
|
||||
export let utc_etag = Date.now()
|
||||
export const main = document.getElementById("main")!
|
||||
export const main = document.getElementById("main")! as HTMLDivElement
|
||||
export const pas_a = document.getElementById("pas")! as HTMLAnchorElement
|
||||
|
||||
const t: typeof document.createElement = (s: string) => document.createElement(s)
|
||||
|
||||
const template = {
|
||||
pasact: {
|
||||
tid: "pasact" as const,
|
||||
nbr: t("input"), send: t("button"),
|
||||
adm: t("section"), adm1: t("select"), adm2: t("select"),
|
||||
pre: t("section"), actid: t("input"), act: t("button"),
|
||||
@@ -33,6 +36,7 @@ const template = {
|
||||
},
|
||||
|
||||
usr: {
|
||||
tid: "usr" as const,
|
||||
idnam: t("a"), id: t("code"), nam: t("span"),
|
||||
adm: t("span"), utc: t("span"),
|
||||
rej: t("span"), ref: t("span"),
|
||||
@@ -46,6 +50,7 @@ const template = {
|
||||
},
|
||||
|
||||
soc: {
|
||||
tid: "soc" as const,
|
||||
idnam: t("a"), id: t("code"), nam: t("span"),
|
||||
adm: t("span"), utc: t("span"),
|
||||
rej: t("span"), ref: t("span"),
|
||||
@@ -56,6 +61,7 @@ const template = {
|
||||
},
|
||||
|
||||
pre: {
|
||||
tid: "pre" as const,
|
||||
idnam: t("a"), id: t("code"), nam: t("span"),
|
||||
meta: t("section"), pnam: t("input"), nbr: t("input"),
|
||||
adm: t("section"), adm1: t("select"), adm2: t("select"),
|
||||
@@ -64,6 +70,7 @@ const template = {
|
||||
},
|
||||
|
||||
putusr: {
|
||||
tid: "putusr" as const,
|
||||
idnam: t("a"), id: t("code"),
|
||||
nam: t("input"),
|
||||
adm1: t("select"), adm2: t("select"),
|
||||
@@ -72,6 +79,7 @@ const template = {
|
||||
},
|
||||
|
||||
idnull: {
|
||||
tid: "idnull" as const,
|
||||
id: t("cod"),
|
||||
meta: t("section")
|
||||
}
|
||||
@@ -90,5 +98,6 @@ export function bind<
|
||||
c, t.querySelector(`.${c}`) as HTMLElement
|
||||
])
|
||||
]) as Template[T] & { bind: DocumentFragment }
|
||||
b.tid = tid
|
||||
return b
|
||||
}
|
||||
|
@@ -155,6 +155,12 @@ section>p {
|
||||
padding: 1ch;
|
||||
}
|
||||
|
||||
section>span:empty::before,
|
||||
section>p:empty::before {
|
||||
color: var(--gray);
|
||||
content: "无";
|
||||
}
|
||||
|
||||
section>textarea {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
@@ -180,6 +186,20 @@ section>select {
|
||||
padding: 0.2ch 1ch;
|
||||
}
|
||||
|
||||
section>span>a:not(:first-child):before,
|
||||
section>p>a:not(:first-child):before {
|
||||
content: "、";
|
||||
color: initial;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
|
||||
section>span>a:hover,
|
||||
section>p>a:hover {
|
||||
color: var(--amber);
|
||||
}
|
||||
}
|
||||
|
||||
div#main {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
@@ -279,25 +299,19 @@ section.meta>span {
|
||||
color: var(--black)
|
||||
}
|
||||
|
||||
section.meta>span.red {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
section.meta>span.green {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
section.meta>span.gray {
|
||||
section.meta>span.rejc,
|
||||
section.meta>span.refc,
|
||||
section.meta>span.proc {
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
section.meta>span>a:hover {
|
||||
color: var(--amber);
|
||||
section.meta>span.red {
|
||||
color: var(--red) !important;
|
||||
}
|
||||
|
||||
section.meta>span>a:not(:first-child):before {
|
||||
content: "、";
|
||||
color: initial;
|
||||
section.meta>span.green,
|
||||
section.meta>span.green:empty::before {
|
||||
color: var(--green) !important;
|
||||
}
|
||||
|
||||
a.idnam {
|
||||
@@ -318,10 +332,12 @@ a.idnam>code.id.active {
|
||||
}
|
||||
|
||||
a.idnam>code.id.red {
|
||||
border: none;
|
||||
background: var(--red) !important;
|
||||
}
|
||||
|
||||
a.idnam>code.id.green {
|
||||
border: none;
|
||||
background: var(--green) !important;
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template id="pasact">
|
||||
<article>
|
||||
<section>
|
||||
<a class="idnam"><code class="id active">pas</code> <span class="nam">用户登录与激活</span></a>
|
||||
<a class="idnam" href="#pas"><code class="id active">pas</code> <span class="nam">用户登录与激活</span></a>
|
||||
</section>
|
||||
<hr>
|
||||
<section class="flex">
|
||||
@@ -145,7 +145,7 @@
|
||||
<section class="meta"></section>
|
||||
<hr>
|
||||
<section class="flex">
|
||||
<label>名称:(2-16个中文字符,不能重复)</label>
|
||||
<label>名称:(2-16个中文字符)</label>
|
||||
<input class="pnam" type="text" maxlength="16" required />
|
||||
</section>
|
||||
<section class="flex">
|
||||
@@ -201,7 +201,7 @@
|
||||
<template id="idnull">
|
||||
<article>
|
||||
<section>
|
||||
<a class="idnam" href=""><code class="id active"></code> <span class="nam">无效操作</span></a>
|
||||
<a class="idnam" href=""><code class="id active"></code> <span class="nam">无效链接</span></a>
|
||||
</section>
|
||||
<hr>
|
||||
<section class="meta"></section>
|
||||
|
Reference in New Issue
Block a user