| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- import { LitElement, html, css, nothing } from 'lit';
- import { useTokens, define } from '../components/base.js';
- import { href, setQuery } from '../utils/router.js';
- import { sampleService } from '../services/sample-data.js';
- import { t } from '../pages/shared.js';
- import '../pages/view-cockpit.js';
- import '../pages/view-intel.js';
- import '../pages/view-coop.js';
- import '../pages/view-review.js';
- import '../pages/view-class.js';
- import '../pages/sample-detail.js';
- const NAV = [['cockpit', '创新驾驶舱'], ['intel', '情报与洞察'], ['coop', '产品共创'], ['review', '验证与评审'], ['class', '课堂与成果']];
- export class SampleShell extends LitElement {
- static properties = { view: { type: String }, filters: { type: Object }, _model: { state: true }, _error: { state: true }, _message: { state: true } };
- constructor() { super(); this.view = 'cockpit'; this.filters = {}; this._model = null; this._error = ''; this._message = ''; }
- connectedCallback() {
- super.connectedCallback(); useTokens(this);
- this.unsubscribe = sampleService.subscribe((model) => { this._model = model; });
- this.load();
- }
- disconnectedCallback() { this.unsubscribe?.(); super.disconnectedCallback(); }
- async load() { this._error = ''; try { this._model = await sampleService.load(); } catch (e) { this._error = e.message; } }
- open(event) { event.stopPropagation(); setQuery({ detail: event.detail.type, record: event.detail.id }); }
- async write(event) {
- event.stopPropagation();
- const { action, input, revision, resolve, reject } = event.detail;
- try { sampleService.mutate(action, input, revision); this._message = '已保存到本机演示空间'; resolve(); }
- catch (e) { reject(e); }
- }
- reset() {
- try { sampleService.reset(); this._message = '已恢复基线;只清除本演示空间的本机修改'; }
- catch (e) { this._message = e.message; }
- }
- renderView() {
- const m = this._model, q = this.filters;
- switch (this.view) {
- case 'cockpit': return html`<view-cockpit .model=${m} .filters=${q}></view-cockpit>`;
- case 'intel': return html`<view-intel .model=${m} .filters=${q}></view-intel>`;
- case 'coop': return html`<view-coop .model=${m} .filters=${q}></view-coop>`;
- case 'review': return html`<view-review .model=${m} .filters=${q}></view-review>`;
- case 'class': return html`<view-class .model=${m} .filters=${q}></view-class>`;
- default: return nothing;
- }
- }
- render() {
- return html`<header><a class="brand" href=${href('/showcase')} data-link><b>康</b><span>产品创新工作坊<small>资料、协作与产品进程</small></span></a><nav aria-label="工作坊功能导航">${NAV.map(([key, label]) => html`<a href=${href('/' + key)} data-link aria-current=${this.view === key ? 'page' : nothing}>${label}</a>`)}</nav><a class="intro-link" href=${href('/showcase')} data-link>方案介绍 ↗</a></header>
- <div class="sample-strip"><strong>模拟演示</strong><span>${t('334条基线 · 12个项目 · 公开浏览,无需登录')}</span><button @click=${() => this.reset()} ?disabled=${!this._model}>重置本机演示</button></div>
- ${this._message ? html`<div class="message" role="status">${this._message}<button aria-label="关闭提示" @click=${() => { this._message = ''; }}>×</button></div>` : nothing}
- <main @sample-open=${(e) => this.open(e)}>${this._error ? html`<div class="empty" role="alert"><h1>模拟资料读取失败</h1><p>${this._error}</p><button @click=${() => this.load()}>重试</button></div>` : this._model ? this.renderView() : html`<div class="empty" role="status">正在读取模拟资料…</div>`}</main>
- <footer>${this._model ? t(`基线${this._model.baselineEntityCount}条,扩展另列:${this._model.extensionCounts.voices}条声音 / ${this._model.extensionCounts.observations}条商品观察 / ${this._model.extensionCounts.prices}条价格 / ${this._model.extensionCounts.citations}条新增引文 / ${this._model.extensionCounts.researchTasks}项研究任务 / ${this._model.extensionCounts.collaborationRecords}条协作。`) : ''}<p>全部扩展记录为模拟。课堂完成不代表需求、实物或量产验证通过。</p></footer>
- ${this._model ? html`<sample-detail .model=${this._model} .recordType=${this.filters.detail || ''} .recordId=${this.filters.record || ''} @sample-open=${(e) => this.open(e)} @sample-close=${() => setQuery({ detail: null, record: null })} @sample-write=${(e) => this.write(e)}></sample-detail>` : nothing}`;
- }
- static styles = css`
- :host{display:block;position:relative;z-index:1;min-height:100vh;background:var(--kf-paper);color:var(--kf-ink);font-family:var(--kf-font);line-height:1.7}*{box-sizing:border-box}a{color:inherit;text-decoration:none}header{background:#fff;border-bottom:1px solid #e1e0e8;display:flex;align-items:center;gap:30px;padding:14px 28px;position:sticky;top:0;z-index:5}.brand{display:flex;align-items:center;gap:10px;white-space:nowrap;font-size:13px;font-weight:600}.brand>b{width:36px;height:36px;display:grid;place-items:center;background:var(--kf-accent);color:#fff;border-radius:8px;font-size:21px}.brand small{display:block;font-size:10px;color:var(--kf-ink-3);font-weight:400}nav{display:flex;align-items:center;gap:5px;margin-left:auto}nav a{padding:9px 13px;font-size:13px;border-radius:6px;white-space:nowrap}nav a>span{font-size:10px;color:var(--kf-ink-3);margin-right:8px}nav a[aria-current=page]{color:var(--kf-accent-ink);background:var(--kf-accent-soft);font-weight:550}.intro-link{font-size:11px;color:var(--kf-ink-3);white-space:nowrap}.sample-strip{display:flex;gap:14px;align-items:center;background:#efedf9;border-bottom:1px solid #dfdbea;font-size:11px;padding:10px max(28px,calc((100vw - 1440px)/2 + 28px));color:#555073}.sample-strip strong{font-weight:600}.sample-strip button{margin-left:auto;font-size:11px;background:#fff;border:1px solid #d4d0e6;border-radius:5px;padding:6px 10px;color:#554d7c;white-space:nowrap;cursor:pointer}.sample-strip button:disabled{opacity:.4}.message{max-width:1384px;margin:14px auto 0;background:#edf4ef;color:#24513a;border:1px solid #ccdfd2;border-radius:6px;padding:10px 15px;font-size:12px;display:flex;justify-content:space-between}.message button{border:0;background:none;font-size:18px;color:inherit;cursor:pointer}main{max-width:1440px;margin:auto;padding:22px 28px 40px;min-height:60vh}.empty{padding:70px 0}.empty h1{font-size:23px}.empty p{font-size:14px}.empty button{font:inherit;border:1px solid #ccc;background:#fff;padding:8px 15px;border-radius:6px;cursor:pointer}footer{max-width:1384px;margin:auto;padding:24px 0 36px;border-top:1px solid #dcdbe6;color:var(--kf-ink-3);font-size:11px}footer p{margin:10px 0 0}a:focus-visible,button:focus-visible{outline:3px solid var(--kf-focus);outline-offset:3px}@media(max-width:1100px){header{flex-wrap:wrap;gap:12px;padding:14px 22px}nav{order:3;flex-basis:100%;margin-left:0;overflow:auto}.intro-link{margin-left:auto}nav a{font-size:12px;padding:7px 12px}.sample-strip{padding:10px 22px}main{padding:16px 22px 36px}footer{margin:0 22px}}@media(max-width:767px){header{padding:12px 16px}.brand{font-size:12px}.brand small{font-size:9px}.brand>b{width:31px;height:31px;font-size:18px}nav a{font-size:11px;padding:8px 9px}nav a>span{margin-right:5px}.sample-strip{padding:10px 16px;flex-wrap:wrap;gap:6px 10px}.sample-strip>span{flex-basis:70%;font-size:10px}.sample-strip button{margin-left:0}main{padding:14px 16px 30px}footer{margin:0 16px;padding:20px 0 30px}.message{margin:12px 16px 0}}
- `;
- }
- define('sample-shell', SampleShell);
|