diff --git a/db.sql b/db.sql
index 74522e3..774d113 100644
--- a/db.sql
+++ b/db.sql
@@ -35,6 +35,9 @@ INSERT INTO article(title,publish_time,description,content,category) VALUES('测
INSERT INTO article(title,publish_time,description,content,category) VALUES('测试5','2022-05-10 16:52:09','测试测试','测试测试测试测试','默认');
INSERT INTO article(title,publish_time,description,content,category) VALUES('测试6','2022-05-10 16:52:09','测试测试','测试测试测试测试','默认');
INSERT INTO article(title,publish_time,description,content,category) VALUES('测试7','2022-05-10 16:52:09','测试测试','测试测试测试测试','默认');
+
+
+update article set cover = 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png'
-- 评论表: 评论ID、文章ID、评论内容、发布时间、评论者IP
create table comment
(
diff --git a/public/index.html b/public/index.html
index 96de575..13e1929 100644
--- a/public/index.html
+++ b/public/index.html
@@ -7,26 +7,136 @@
-
{{title}}
-
-
xxxx
+
+
+
+
+
![]()
+
+
+
{{a.title}}
+
{{a.description}}
+
+ 发布于:2022-5-11
+ 阅读(20)
+ 评论(10)
+
+
+
+
+
+
+
+
diff --git a/public/index_v3.html b/public/index_v3.html
new file mode 100644
index 0000000..9b1bb2e
--- /dev/null
+++ b/public/index_v3.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
Document
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/login.html b/public/login.html
new file mode 100644
index 0000000..e69de29
diff --git a/public/modules/request.js b/public/modules/request.js
new file mode 100644
index 0000000..71096af
--- /dev/null
+++ b/public/modules/request.js
@@ -0,0 +1,36 @@
+/**
+ * example:
+ *
request('http://localhost:3000/aricle/detail?id=1').then()...
+ * request('http://localhost:3000/aricle/detail',{id:1}).then()...
+ * request('http://localhost:3000/aricle/detail',{id:1},'POST').then()...
+ * @param {string} url
+ * @param {*} params
+ * @param {'GET'|'POST'} method
+ * @returns
+ */
+const request = (url, params = {}, method = 'GET') => {
+ return new Promise((resovle, reject) => {
+ const options = {
+ method: method
+ }
+ if (method.toUpperCase() == 'GET') {
+ const query = [];
+ for (let key in params) {
+
+ query.push(`${key}=` + params[key]);
+ }
+ url = url + (url.includes('?') ? "&" : "?") + query.join('&')
+ } else {
+ options.headers = {
+ 'Content-Type': 'application/json'
+ }
+ options.body = JSON.stringify(params) // 对象转json
+ }
+ fetch(url, options)
+ .then(res => res.json())
+ .then(resovle)
+ .catch(e => reject(e))
+ });
+}
+//
+export default request
\ No newline at end of file
diff --git a/public/vue/dist/vue_3.js b/public/vue/dist/vue_3.js
new file mode 100644
index 0000000..087f669
--- /dev/null
+++ b/public/vue/dist/vue_3.js
@@ -0,0 +1,15839 @@
+var Vue = (function (exports) {
+ 'use strict';
+
+ /**
+ * Make a map and return a function for checking if a key
+ * is in that map.
+ * IMPORTANT: all calls of this function must be prefixed with
+ * \/\*#\_\_PURE\_\_\*\/
+ * So that rollup can tree-shake them if necessary.
+ */
+ function makeMap(str, expectsLowerCase) {
+ const map = Object.create(null);
+ const list = str.split(',');
+ for (let i = 0; i < list.length; i++) {
+ map[list[i]] = true;
+ }
+ return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val];
+ }
+
+ /**
+ * dev only flag -> name mapping
+ */
+ const PatchFlagNames = {
+ [1 /* TEXT */]: `TEXT`,
+ [2 /* CLASS */]: `CLASS`,
+ [4 /* STYLE */]: `STYLE`,
+ [8 /* PROPS */]: `PROPS`,
+ [16 /* FULL_PROPS */]: `FULL_PROPS`,
+ [32 /* HYDRATE_EVENTS */]: `HYDRATE_EVENTS`,
+ [64 /* STABLE_FRAGMENT */]: `STABLE_FRAGMENT`,
+ [128 /* KEYED_FRAGMENT */]: `KEYED_FRAGMENT`,
+ [256 /* UNKEYED_FRAGMENT */]: `UNKEYED_FRAGMENT`,
+ [512 /* NEED_PATCH */]: `NEED_PATCH`,
+ [1024 /* DYNAMIC_SLOTS */]: `DYNAMIC_SLOTS`,
+ [2048 /* DEV_ROOT_FRAGMENT */]: `DEV_ROOT_FRAGMENT`,
+ [-1 /* HOISTED */]: `HOISTED`,
+ [-2 /* BAIL */]: `BAIL`
+ };
+
+ /**
+ * Dev only
+ */
+ const slotFlagsText = {
+ [1 /* STABLE */]: 'STABLE',
+ [2 /* DYNAMIC */]: 'DYNAMIC',
+ [3 /* FORWARDED */]: 'FORWARDED'
+ };
+
+ const GLOBALS_WHITE_LISTED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
+ 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
+ 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt';
+ const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED);
+
+ const range = 2;
+ function generateCodeFrame(source, start = 0, end = source.length) {
+ // Split the content into individual lines but capture the newline sequence
+ // that separated each line. This is important because the actual sequence is
+ // needed to properly take into account the full line length for offset
+ // comparison
+ let lines = source.split(/(\r?\n)/);
+ // Separate the lines and newline sequences into separate arrays for easier referencing
+ const newlineSequences = lines.filter((_, idx) => idx % 2 === 1);
+ lines = lines.filter((_, idx) => idx % 2 === 0);
+ let count = 0;
+ const res = [];
+ for (let i = 0; i < lines.length; i++) {
+ count +=
+ lines[i].length +
+ ((newlineSequences[i] && newlineSequences[i].length) || 0);
+ if (count >= start) {
+ for (let j = i - range; j <= i + range || end > count; j++) {
+ if (j < 0 || j >= lines.length)
+ continue;
+ const line = j + 1;
+ res.push(`${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`);
+ const lineLength = lines[j].length;
+ const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0;
+ if (j === i) {
+ // push underline
+ const pad = start - (count - (lineLength + newLineSeqLength));
+ const length = Math.max(1, end > count ? lineLength - pad : end - start);
+ res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length));
+ }
+ else if (j > i) {
+ if (end > count) {
+ const length = Math.max(Math.min(end - count, lineLength), 1);
+ res.push(` | ` + '^'.repeat(length));
+ }
+ count += lineLength + newLineSeqLength;
+ }
+ }
+ break;
+ }
+ }
+ return res.join('\n');
+ }
+
+ /**
+ * On the client we only need to offer special cases for boolean attributes that
+ * have different names from their corresponding dom properties:
+ * - itemscope -> N/A
+ * - allowfullscreen -> allowFullscreen
+ * - formnovalidate -> formNoValidate
+ * - ismap -> isMap
+ * - nomodule -> noModule
+ * - novalidate -> noValidate
+ * - readonly -> readOnly
+ */
+ const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;
+ const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs);
+ /**
+ * Boolean attributes should be included if the value is truthy or ''.
+ * e.g. `