Explorar o código

Merge branch 'dev' of http://1.94.207.143:3000/xyy/xyy-m into dev

qiao hai 3 meses
pai
achega
161415668b
Modificáronse 53 ficheiros con 2122 adicións e 54 borrados
  1. 2 1
      nuxt.config.ts
  2. 4 0
      src/app.vue
  3. 539 0
      src/assets/iconfont/demo.css
  4. 603 0
      src/assets/iconfont/demo_index.html
  5. 88 0
      src/assets/iconfont/iconfont.css
  6. 0 0
      src/assets/iconfont/iconfont.js
  7. 135 0
      src/assets/iconfont/iconfont.json
  8. 30 0
      src/assets/iconfont/iconfont.svg
  9. BIN=BIN
      src/assets/iconfont/iconfont.ttf
  10. BIN=BIN
      src/assets/iconfont/iconfont.woff
  11. BIN=BIN
      src/assets/iconfont/iconfont.woff2
  12. BIN=BIN
      src/assets/img/empty.png
  13. BIN=BIN
      src/assets/img/login/login_bg.png
  14. BIN=BIN
      src/assets/img/logo.png
  15. 1 0
      src/assets/img/note-create/cancel.svg
  16. BIN=BIN
      src/assets/img/note-create/create_note_days.png
  17. BIN=BIN
      src/assets/img/note-create/create_note_endplace.jpg
  18. BIN=BIN
      src/assets/img/note-create/create_note_fee.png
  19. BIN=BIN
      src/assets/img/note-create/create_note_insert_img.png
  20. BIN=BIN
      src/assets/img/note-create/create_note_insert_title.png
  21. BIN=BIN
      src/assets/img/note-create/create_note_relation.png
  22. BIN=BIN
      src/assets/img/note-create/create_note_save_tmp.png
  23. BIN=BIN
      src/assets/img/note-create/create_note_star.png
  24. BIN=BIN
      src/assets/img/note-create/create_note_startdate.png
  25. BIN=BIN
      src/assets/img/note-create/create_note_title.png
  26. BIN=BIN
      src/assets/img/note-create/create_note_travel_mode.png
  27. BIN=BIN
      src/assets/img/note-create/create_note_travel_number.png
  28. BIN=BIN
      src/assets/img/note-create/note_create_banner_bg.png
  29. BIN=BIN
      src/assets/img/note-create/note_create_bg.png
  30. BIN=BIN
      src/assets/img/note-create/note_create_book.png
  31. BIN=BIN
      src/assets/img/note-create/note_create_content_bg.png
  32. BIN=BIN
      src/assets/img/note-create/note_create_entry.png
  33. BIN=BIN
      src/assets/img/note-create/note_create_start_icon.png
  34. BIN=BIN
      src/assets/img/note-create/note_create_success.png
  35. BIN=BIN
      src/assets/img/note-create/note_draft_cover_bg.jpg
  36. BIN=BIN
      src/assets/img/note-create/userinfo_modal.jpg
  37. 11 11
      src/components/Home/Menu.vue
  38. 55 0
      src/components/Profile/Notes/Auditing/Item.vue
  39. 60 0
      src/components/Profile/Notes/Auditing/index.vue
  40. 23 0
      src/components/Profile/Notes/Empty.vue
  41. 66 0
      src/components/Profile/Notes/Published/Item.vue
  42. 67 0
      src/components/Profile/Notes/Published/index.vue
  43. 38 0
      src/components/Profile/Notes/Tabs.vue
  44. 3 2
      src/components/Tabbar/index.vue
  45. 10 0
      src/composables/useLoading.js
  46. 217 0
      src/pages/login/index.client.vue
  47. 6 0
      src/pages/note-create-start/index.vue
  48. 82 0
      src/pages/profile/index/notes.vue
  49. 19 0
      src/stores/useAuth.js
  50. 27 23
      src/stores/useTabbar.js
  51. 12 0
      src/stores/useUserInfo.js
  52. 10 0
      src/utils/index.js
  53. 14 17
      src/utils/request.js

+ 2 - 1
nuxt.config.ts

@@ -22,6 +22,7 @@ export default defineNuxtConfig({
       "minMax",
     ],
   },
+
   runtimeConfig: {
     public: {
       baseApi: process.env.VITE_APP_BASE_URL,
@@ -51,7 +52,7 @@ export default defineNuxtConfig({
       ],
     },
   },
-  css: ["@/assets/css/tailwind.css"],
+  css: ["@/assets/css/tailwind.css", "./src/assets/iconfont/iconfont.css"],
   postcss: {
     plugins: {
       tailwindcss: {},

+ 4 - 0
src/app.vue

@@ -11,5 +11,9 @@ const themeVars = reactive({
   buttonPrimaryBackground: "#22C2A0",
   buttonPrimaryBorderColor: "#22C2A0",
   searchPadding: "0px",
+  dividerLineHeight: "1px",
+  dividerContentPadding: "0",
+  dividerMargin: "0",
+  dividerVerticalMargin: "0",
 });
 </script>

+ 539 - 0
src/assets/iconfont/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

+ 603 - 0
src/assets/iconfont/demo_index.html

@@ -0,0 +1,603 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>iconfont Demo</title>
+  <link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
+  <link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+  <style>
+    .main .logo {
+      margin-top: 0;
+      height: auto;
+    }
+
+    .main .logo a {
+      display: flex;
+      align-items: center;
+    }
+
+    .main .logo .sub-title {
+      margin-left: 0.5em;
+      font-size: 22px;
+      color: #fff;
+      background: linear-gradient(-45deg, #3967FF, #B500FE);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  </style>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
+      <img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
+      
+    </a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4723464" target="_blank" class="nav-more">查看项目</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78a;</span>
+                <div class="name">message</div>
+                <div class="code-name">&amp;#xe78a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe783;</span>
+                <div class="name">smile</div>
+                <div class="code-name">&amp;#xe783;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe7df;</span>
+                <div class="name">star</div>
+                <div class="code-name">&amp;#xe7df;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe86b;</span>
+                <div class="name">star-fill</div>
+                <div class="code-name">&amp;#xe86b;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe8fe;</span>
+                <div class="name">plus</div>
+                <div class="code-name">&amp;#xe8fe;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe791;</span>
+                <div class="name">edit-square</div>
+                <div class="code-name">&amp;#xe791;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe7c3;</span>
+                <div class="name">delete</div>
+                <div class="code-name">&amp;#xe7c3;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe78e;</span>
+                <div class="name">setting</div>
+                <div class="code-name">&amp;#xe78e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe845;</span>
+                <div class="name">plus-circle-fill</div>
+                <div class="code-name">&amp;#xe845;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe860;</span>
+                <div class="name">image-fill</div>
+                <div class="code-name">&amp;#xe860;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe7fc;</span>
+                <div class="name">close</div>
+                <div class="code-name">&amp;#xe7fc;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe8ec;</span>
+                <div class="name">caret-down</div>
+                <div class="code-name">&amp;#xe8ec;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe868;</span>
+                <div class="name">location-fill</div>
+                <div class="code-name">&amp;#xe868;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe866;</span>
+                <div class="name">fire-fill</div>
+                <div class="code-name">&amp;#xe866;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe869;</span>
+                <div class="name">eye-fill</div>
+                <div class="code-name">&amp;#xe869;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe86a;</span>
+                <div class="name">like-fill</div>
+                <div class="code-name">&amp;#xe86a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60d;</span>
+                <div class="name">arrow_right</div>
+                <div class="code-name">&amp;#xe60d;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60f;</span>
+                <div class="name">profile</div>
+                <div class="code-name">&amp;#xe60f;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.woff2?t=1731999413855') format('woff2'),
+       url('iconfont.woff?t=1731999413855') format('woff'),
+       url('iconfont.ttf?t=1731999413855') format('truetype'),
+       url('iconfont.svg?t=1731999413855#iconfont') format('svg');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont icon-message"></span>
+            <div class="name">
+              message
+            </div>
+            <div class="code-name">.icon-message
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-smile"></span>
+            <div class="name">
+              smile
+            </div>
+            <div class="code-name">.icon-smile
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-star"></span>
+            <div class="name">
+              star
+            </div>
+            <div class="code-name">.icon-star
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-star-fill"></span>
+            <div class="name">
+              star-fill
+            </div>
+            <div class="code-name">.icon-star-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-plus"></span>
+            <div class="name">
+              plus
+            </div>
+            <div class="code-name">.icon-plus
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-edit-square"></span>
+            <div class="name">
+              edit-square
+            </div>
+            <div class="code-name">.icon-edit-square
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-delete"></span>
+            <div class="name">
+              delete
+            </div>
+            <div class="code-name">.icon-delete
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-setting"></span>
+            <div class="name">
+              setting
+            </div>
+            <div class="code-name">.icon-setting
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-plus-circle-fill"></span>
+            <div class="name">
+              plus-circle-fill
+            </div>
+            <div class="code-name">.icon-plus-circle-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-image-fill"></span>
+            <div class="name">
+              image-fill
+            </div>
+            <div class="code-name">.icon-image-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-close"></span>
+            <div class="name">
+              close
+            </div>
+            <div class="code-name">.icon-close
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-caret-down"></span>
+            <div class="name">
+              caret-down
+            </div>
+            <div class="code-name">.icon-caret-down
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-location-fill"></span>
+            <div class="name">
+              location-fill
+            </div>
+            <div class="code-name">.icon-location-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-fire-fill"></span>
+            <div class="name">
+              fire-fill
+            </div>
+            <div class="code-name">.icon-fire-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-eye-fill"></span>
+            <div class="name">
+              eye-fill
+            </div>
+            <div class="code-name">.icon-eye-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-like-fill"></span>
+            <div class="name">
+              like-fill
+            </div>
+            <div class="code-name">.icon-like-fill
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-arrow_right"></span>
+            <div class="name">
+              arrow_right
+            </div>
+            <div class="code-name">.icon-arrow_right
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-profile"></span>
+            <div class="name">
+              profile
+            </div>
+            <div class="code-name">.icon-profile
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-message"></use>
+                </svg>
+                <div class="name">message</div>
+                <div class="code-name">#icon-message</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-smile"></use>
+                </svg>
+                <div class="name">smile</div>
+                <div class="code-name">#icon-smile</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-star"></use>
+                </svg>
+                <div class="name">star</div>
+                <div class="code-name">#icon-star</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-star-fill"></use>
+                </svg>
+                <div class="name">star-fill</div>
+                <div class="code-name">#icon-star-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-plus"></use>
+                </svg>
+                <div class="name">plus</div>
+                <div class="code-name">#icon-plus</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-edit-square"></use>
+                </svg>
+                <div class="name">edit-square</div>
+                <div class="code-name">#icon-edit-square</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-delete"></use>
+                </svg>
+                <div class="name">delete</div>
+                <div class="code-name">#icon-delete</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-setting"></use>
+                </svg>
+                <div class="name">setting</div>
+                <div class="code-name">#icon-setting</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-plus-circle-fill"></use>
+                </svg>
+                <div class="name">plus-circle-fill</div>
+                <div class="code-name">#icon-plus-circle-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-image-fill"></use>
+                </svg>
+                <div class="name">image-fill</div>
+                <div class="code-name">#icon-image-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-close"></use>
+                </svg>
+                <div class="name">close</div>
+                <div class="code-name">#icon-close</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-caret-down"></use>
+                </svg>
+                <div class="name">caret-down</div>
+                <div class="code-name">#icon-caret-down</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-location-fill"></use>
+                </svg>
+                <div class="name">location-fill</div>
+                <div class="code-name">#icon-location-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-fire-fill"></use>
+                </svg>
+                <div class="name">fire-fill</div>
+                <div class="code-name">#icon-fire-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-eye-fill"></use>
+                </svg>
+                <div class="name">eye-fill</div>
+                <div class="code-name">#icon-eye-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-like-fill"></use>
+                </svg>
+                <div class="name">like-fill</div>
+                <div class="code-name">#icon-like-fill</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-arrow_right"></use>
+                </svg>
+                <div class="name">arrow_right</div>
+                <div class="code-name">#icon-arrow_right</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-profile"></use>
+                </svg>
+                <div class="name">profile</div>
+                <div class="code-name">#icon-profile</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>

+ 88 - 0
src/assets/iconfont/iconfont.css

@@ -0,0 +1,88 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 4723464 */
+  src: url('iconfont.woff2?t=1731999413855') format('woff2'),
+       url('iconfont.woff?t=1731999413855') format('woff'),
+       url('iconfont.ttf?t=1731999413855') format('truetype'),
+       url('iconfont.svg?t=1731999413855#iconfont') format('svg');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-message:before {
+  content: "\e78a";
+}
+
+.icon-smile:before {
+  content: "\e783";
+}
+
+.icon-star:before {
+  content: "\e7df";
+}
+
+.icon-star-fill:before {
+  content: "\e86b";
+}
+
+.icon-plus:before {
+  content: "\e8fe";
+}
+
+.icon-edit-square:before {
+  content: "\e791";
+}
+
+.icon-delete:before {
+  content: "\e7c3";
+}
+
+.icon-setting:before {
+  content: "\e78e";
+}
+
+.icon-plus-circle-fill:before {
+  content: "\e845";
+}
+
+.icon-image-fill:before {
+  content: "\e860";
+}
+
+.icon-close:before {
+  content: "\e7fc";
+}
+
+.icon-caret-down:before {
+  content: "\e8ec";
+}
+
+.icon-location-fill:before {
+  content: "\e868";
+}
+
+.icon-fire-fill:before {
+  content: "\e866";
+}
+
+.icon-eye-fill:before {
+  content: "\e869";
+}
+
+.icon-like-fill:before {
+  content: "\e86a";
+}
+
+.icon-arrow_right:before {
+  content: "\e60d";
+}
+
+.icon-profile:before {
+  content: "\e60f";
+}
+

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/assets/iconfont/iconfont.js


+ 135 - 0
src/assets/iconfont/iconfont.json

@@ -0,0 +1,135 @@
+{
+  "id": "4723464",
+  "name": "xyy-web",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "4765866",
+      "name": "message",
+      "font_class": "message",
+      "unicode": "e78a",
+      "unicode_decimal": 59274
+    },
+    {
+      "icon_id": "4765739",
+      "name": "smile",
+      "font_class": "smile",
+      "unicode": "e783",
+      "unicode_decimal": 59267
+    },
+    {
+      "icon_id": "4766954",
+      "name": "star",
+      "font_class": "star",
+      "unicode": "e7df",
+      "unicode_decimal": 59359
+    },
+    {
+      "icon_id": "4936673",
+      "name": "star-fill",
+      "font_class": "star-fill",
+      "unicode": "e86b",
+      "unicode_decimal": 59499
+    },
+    {
+      "icon_id": "7834345",
+      "name": "plus",
+      "font_class": "plus",
+      "unicode": "e8fe",
+      "unicode_decimal": 59646
+    },
+    {
+      "icon_id": "4765957",
+      "name": "edit-square",
+      "font_class": "edit-square",
+      "unicode": "e791",
+      "unicode_decimal": 59281
+    },
+    {
+      "icon_id": "4766676",
+      "name": "delete",
+      "font_class": "delete",
+      "unicode": "e7c3",
+      "unicode_decimal": 59331
+    },
+    {
+      "icon_id": "4765891",
+      "name": "setting",
+      "font_class": "setting",
+      "unicode": "e78e",
+      "unicode_decimal": 59278
+    },
+    {
+      "icon_id": "4936486",
+      "name": "plus-circle-fill",
+      "font_class": "plus-circle-fill",
+      "unicode": "e845",
+      "unicode_decimal": 59461
+    },
+    {
+      "icon_id": "4936630",
+      "name": "image-fill",
+      "font_class": "image-fill",
+      "unicode": "e860",
+      "unicode_decimal": 59488
+    },
+    {
+      "icon_id": "4767096",
+      "name": "close",
+      "font_class": "close",
+      "unicode": "e7fc",
+      "unicode_decimal": 59388
+    },
+    {
+      "icon_id": "6598339",
+      "name": "caret-down",
+      "font_class": "caret-down",
+      "unicode": "e8ec",
+      "unicode_decimal": 59628
+    },
+    {
+      "icon_id": "4936659",
+      "name": "location-fill",
+      "font_class": "location-fill",
+      "unicode": "e868",
+      "unicode_decimal": 59496
+    },
+    {
+      "icon_id": "4936652",
+      "name": "fire-fill",
+      "font_class": "fire-fill",
+      "unicode": "e866",
+      "unicode_decimal": 59494
+    },
+    {
+      "icon_id": "4936668",
+      "name": "eye-fill",
+      "font_class": "eye-fill",
+      "unicode": "e869",
+      "unicode_decimal": 59497
+    },
+    {
+      "icon_id": "4936669",
+      "name": "like-fill",
+      "font_class": "like-fill",
+      "unicode": "e86a",
+      "unicode_decimal": 59498
+    },
+    {
+      "icon_id": "14678715",
+      "name": "arrow_right",
+      "font_class": "arrow_right",
+      "unicode": "e60d",
+      "unicode_decimal": 58893
+    },
+    {
+      "icon_id": "11813183",
+      "name": "profile",
+      "font_class": "profile",
+      "unicode": "e60f",
+      "unicode_decimal": 58895
+    }
+  ]
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 30 - 0
src/assets/iconfont/iconfont.svg


BIN=BIN
src/assets/iconfont/iconfont.ttf


BIN=BIN
src/assets/iconfont/iconfont.woff


BIN=BIN
src/assets/iconfont/iconfont.woff2


BIN=BIN
src/assets/img/empty.png


BIN=BIN
src/assets/img/login/login_bg.png


BIN=BIN
src/assets/img/logo.png


+ 1 - 0
src/assets/img/note-create/cancel.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15" height="15" viewBox="0 0 15 15"><defs><style>.a{fill:#fff;stroke:#707070;}.b{clip-path:url(#a);}.c{fill:#fd9a00;stroke:#fd9a00;}</style><clipPath id="a"><rect class="a" width="15" height="15" transform="translate(193 256)"/></clipPath></defs><g class="b" transform="translate(-193 -256)"><g transform="translate(140.761 226.944)"><path class="c" d="M59.656,108.558a6.659,6.659,0,0,1-5.742-10.024,6.7,6.7,0,0,1,2.4-2.388.291.291,0,0,1,.293.5,6.073,6.073,0,1,0,4.033-.741.292.292,0,1,1,.095-.576,6.657,6.657,0,0,1-1.077,13.227Z" transform="translate(0 -64.992)"/><path class="c" d="M461.86,29.378l-2.448.6a.161.161,0,0,0-.079.267l1.776,1.859a.161.161,0,0,0,.271-.069l.673-2.457a.161.161,0,0,0-.193-.2Z" transform="translate(-400.361)"/></g></g></svg>

BIN=BIN
src/assets/img/note-create/create_note_days.png


BIN=BIN
src/assets/img/note-create/create_note_endplace.jpg


BIN=BIN
src/assets/img/note-create/create_note_fee.png


BIN=BIN
src/assets/img/note-create/create_note_insert_img.png


BIN=BIN
src/assets/img/note-create/create_note_insert_title.png


BIN=BIN
src/assets/img/note-create/create_note_relation.png


BIN=BIN
src/assets/img/note-create/create_note_save_tmp.png


BIN=BIN
src/assets/img/note-create/create_note_star.png


BIN=BIN
src/assets/img/note-create/create_note_startdate.png


BIN=BIN
src/assets/img/note-create/create_note_title.png


BIN=BIN
src/assets/img/note-create/create_note_travel_mode.png


BIN=BIN
src/assets/img/note-create/create_note_travel_number.png


BIN=BIN
src/assets/img/note-create/note_create_banner_bg.png


BIN=BIN
src/assets/img/note-create/note_create_bg.png


BIN=BIN
src/assets/img/note-create/note_create_book.png


BIN=BIN
src/assets/img/note-create/note_create_content_bg.png


BIN=BIN
src/assets/img/note-create/note_create_entry.png


BIN=BIN
src/assets/img/note-create/note_create_start_icon.png


BIN=BIN
src/assets/img/note-create/note_create_success.png


BIN=BIN
src/assets/img/note-create/note_draft_cover_bg.jpg


BIN=BIN
src/assets/img/note-create/userinfo_modal.jpg


+ 11 - 11
src/components/Home/Menu.vue

@@ -13,27 +13,27 @@
 </template>
 
 <script setup>
-import HomeFoodIcon from "@/assets/img/home_food.png";
-import HomeTravleIcon from "@/assets/img/home_travel.png";
-import HomeLabourIcon from "@/assets/img/home_Labour.png";
+import HomeFoodIcon from '@/assets/img/home_food.png'
+import HomeTravleIcon from '@/assets/img/home_travel.png'
+import HomeLabourIcon from '@/assets/img/home_Labour.png'
 
 const menuData = [
   {
     icon: HomeFoodIcon,
-    title: "境外美食",
-    to: "/food",
+    title: '境外美食',
+    to: '/food'
   },
   {
     icon: HomeTravleIcon,
-    title: "境外旅游",
-    to: "/travel",
+    title: '境外旅游',
+    to: '/travel'
   },
   {
     icon: HomeLabourIcon,
-    title: "出国劳务",
-    to: "/labour",
-  },
-];
+    title: '出国劳务',
+    to: '/labour'
+  }
+]
 </script>
 
 <style lang="scss" scoped></style>

+ 55 - 0
src/components/Profile/Notes/Auditing/Item.vue

@@ -0,0 +1,55 @@
+<template>
+  <div class="group flex space-x-10 p-10 transition-all rounded-xl bg-[#FFF]">
+    <img
+      :src="formatImgSrc(data?.tourismUrlsAfterConvert) || noteDraftCoverBg"
+      class="aspect-[4/3] h-109 shrink-0 object-cover"
+    />
+
+    <div class="flex w-0 flex-1 flex-col justify-between">
+      <div class="mt-18">
+        <div class="line-clamp-1 break-all text-base font-semibold text-black-3">
+          {{ data?.projectTitle || '未命名草稿' }}
+        </div>
+        <div class="mt-2 text-sm text-black-3">
+          {{ $dayjs(data?.updateTime).format('YYYY/MM/DD') }}
+        </div>
+      </div>
+      <div @click="$emit('onRevoke')" class="flex mb-10 items-center space-x-5">
+        <div class="flex cursor-pointer items-center p-5 text-primary">
+          <span class="w-15 h-15">
+            <img
+              class="w-full h-full shrink-0 object-cover"
+              src="~/assets/img/note-create/cancel.svg"
+              alt=""
+            />
+          </span>
+          <span class="text-base">撤销审核</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import noteDraftCoverBg from '~/assets/img/note-create/note_draft_cover_bg.jpg'
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({})
+  }
+})
+
+defineEmits(['onRevoke'])
+
+function handleWrite() {
+  navigateTo({
+    path: '/note-create',
+    query: {
+      id: props.data.id
+    }
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 60 - 0
src/components/Profile/Notes/Auditing/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <div class="w-full min-h-400 pb-10">
+    <!-- v-loading="loading" -->
+    <!-- v-if="!loading && !draftList.length" -->
+    <ProfileNotesEmpty v-if="!draftList.length" />
+    <!-- v-else-if="draftList.length" -->
+    <!-- <div class="flex flex-col divide-y"> -->
+    <div class="flex flex-col divide-y">
+      <ProfileNotesAuditingItem />
+      <!-- v-for="item in draftList"
+        :key="item.id"
+        :data="item"
+        @on-revoke="handleRevoke(item)" -->
+    </div>
+  </div>
+</template>
+
+<script setup>
+// const { loading, setLoading } = useLoading()
+// loading.value = true
+
+const draftList = ref([])
+
+async function getNotesList() {
+  // setLoading(true)
+  try {
+    const { data } = await request('/website/tourism/publishTravelNotes/getDraftList', {
+      query: {
+        pageNum: 1,
+        pageSize: 10000,
+        type: 1
+      }
+    })
+    draftList.value = data.dataList
+  } finally {
+    // setLoading(false)
+  }
+}
+
+async function handleRevoke(item) {
+  ElMessageBox.confirm('确定撤销审核吗?', '提示', {}).then(async () => {
+    try {
+      await request(`/website/tourism/publishTravelNotes/withdraw`, {
+        method: 'post',
+        body: {
+          writeId: item.id
+        }
+      })
+      ElMessage.success('撤销成功')
+      getNotesList()
+    } catch (error) {}
+  })
+}
+
+onMounted(() => {
+  // getNotesList()
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 23 - 0
src/components/Profile/Notes/Empty.vue

@@ -0,0 +1,23 @@
+<template>
+  <div class="flex h-360 flex-col items-center justify-center space-y-10">
+    <img src="~/assets/img/empty.png" class="h-80 object-cover" />
+    <div class="text-base text-[#999999]">{{ title }}</div>
+    <NuxtLink
+      to="/note-create"
+      class="flex cursor-pointer items-center justify-center space-x-10 rounded-sm bg-primary px-20 py-5 text-base text-white hover:opacity-80"
+    >
+      去写游记
+    </NuxtLink>
+  </div>
+</template>
+
+<script setup>
+defineProps({
+  title: {
+    type: String,
+    default: '暂无游记'
+  }
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 66 - 0
src/components/Profile/Notes/Published/Item.vue

@@ -0,0 +1,66 @@
+<template>
+  <van-swipe-cell>
+    <div class="group flex border-box p-10 transition-all mb-10 bg-[#fff] rounded-xl">
+      <div class="aspect-[4/3] h-109 border-box">
+        <van-image
+          width="100%"
+          height="100%"
+          fit="contain"
+          :src="formatImgSrc(data?.tourismUrlsAfterConvert) || noteDraftCoverBg"
+        />
+      </div>
+
+      <div class="flex-1 ml-15">
+        <div class="min-h-70">
+          <NuxtLink
+            :to="`/yj/${data?.id}`"
+            class="cursor-pointer truncate break-all text-base font-bold text-black-3 transition-all hover:text-primary"
+          >
+            {{ data?.projectTitle }}
+          </NuxtLink>
+          <div class="line-clamp-3 text-sm leading-[17px] break-all text-black-6">
+            {{ data?.remarks }}
+          </div>
+        </div>
+        <div class="flex space-x-4 text-sm text-[#FD9A00]">
+          <div class="flex items-center space-x-2">
+            <span class="iconfont icon-eye-fill text-[#FD9A00]" style="font-size: 15px"></span>
+            <div>{{ data?.pageViewCount ?? 0 }}</div>
+          </div>
+          <div v-if="data?.endPlaceDictMap" class="flex items-center space-x-2">
+            <span class="iconfont icon-location-fill text-black-9" style="font-size: 15px"></span>
+            <div>{{ data?.endPlaceDictMap?.name }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <template #right>
+      <van-button
+        square
+        text="下架"
+        @click="$emit('onNoteDown')"
+        type="danger"
+        class="delete-button"
+      />
+    </template>
+  </van-swipe-cell>
+</template>
+
+<script setup>
+import noteDraftCoverBg from '~/assets/img/note-create/note_draft_cover_bg.jpg'
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({})
+  }
+})
+
+defineEmits(['onNoteDown'])
+</script>
+
+<style lang="scss" scoped>
+.delete-button {
+  height: 100%;
+}
+</style>

+ 67 - 0
src/components/Profile/Notes/Published/index.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="w-full box-border min-h-400 pb-10 px-1">
+    <ProfileNotesEmpty v-if="!noteList.length" />
+
+    <ProfileNotesPublishedItem
+      v-for="item in noteList"
+      :key="item.id"
+      :data="item"
+      @on-note-down="handleNoteDown(item)"
+    />
+  </div>
+</template>
+
+<script setup>
+const { loading, setLoading } = useLoading()
+
+const noteList = ref([])
+const pageNum = ref(1)
+
+function getList() {
+  try {
+    // let {
+    //   data: { dataList }
+    // } = await request('/website/tourism/publishTravelNotes/getDraftList', {
+    //   query: {
+    //     pageNum: pageNum.value,
+    //     pageSize: 10,
+    //     type: 3
+    //   }
+    // })
+    let dataList = [
+      {
+        id: '1'
+      }
+    ]
+    console.log(1231)
+    if (Array.isArray(dataList) && dataList.length) {
+      console.log(1231444)
+
+      noteList.value = dataList
+      pageNum.value++
+    }
+  } catch (error) {}
+}
+
+// 下架
+async function handleNoteDown(item) {
+  ElMessageBox.confirm('下架后游记将存入草稿,确定下架吗?', '提示', {}).then(async () => {
+    try {
+      await request(`/website/tourism/publishTravelNotes/delist`, {
+        method: 'post',
+        body: {
+          writeId: item.id
+        }
+      })
+      ElMessage.success('下架成功')
+      getList()
+    } catch (error) {}
+  })
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 38 - 0
src/components/Profile/Notes/Tabs.vue

@@ -0,0 +1,38 @@
+<template>
+  <div>
+    <div class="flex items-center space-x-7 bg-[#F8F8F8] py-16">
+      <div
+        v-for="tab in tabs"
+        :key="tab.lable"
+        @click="handleClick(tab)"
+        class="flex w-78 h-34 text-14 cursor-pointer items-center justify-center rounded-full text-base transition-all"
+        :class="[
+          currentTab == tab.name ? 'bg-primary text-white font-bold' : 'bg-yellow text-black-3'
+        ]"
+      >
+        {{ tab.lable }}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+const props = defineProps({
+  tabs: {
+    type: Array,
+    default: () => []
+  }
+})
+
+const currentTab = useRouteQuery('tab')
+
+function handleClick(tab) {
+  navigateTo({
+    query: {
+      tab: tab.name
+    }
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 3 - 2
src/components/Tabbar/index.vue

@@ -10,12 +10,13 @@
     <van-tabbar-item icon="home-o">首页</van-tabbar-item>
     <van-tabbar-item icon="search">境外旅游</van-tabbar-item>
     <van-tabbar-item icon="friends-o">出国劳务</van-tabbar-item>
+    <van-tabbar-item icon="friends-o">写游记</van-tabbar-item>
   </van-tabbar>
 </template>
 
 <script setup>
-const tabbarStore = useTabbarStore();
-const { index } = storeToRefs(tabbarStore);
+const tabbarStore = useTabbarStore()
+const { index } = storeToRefs(tabbarStore)
 </script>
 
 <style lang="scss" scoped></style>

+ 10 - 0
src/composables/useLoading.js

@@ -0,0 +1,10 @@
+export const useLoading = () => {
+  const loading = ref(false)
+
+  const setLoading = (val) => (loading.value = val)
+
+  return {
+    loading,
+    setLoading
+  }
+}

+ 217 - 0
src/pages/login/index.client.vue

@@ -0,0 +1,217 @@
+<template>
+  <div
+    class="flex flex-col items-center pt-50 bg-[url('~/assets/img/login/login_bg.png')] bg-no-repeat bg-bottom min-h-screen bg-contain"
+  >
+    <img src="~/assets/img/logo.png" class="w-109 h-57" alt="" srcset="" />
+    <span class="text-black-3 mt-40 text-2xl font-semibold">登录到 逍遥游</span>
+    <span class="text-black-6 mt-5 text-base">探寻新视野,趣游山水间</span>
+    <div class="w-full pt-20 px-15">
+      <van-form label-width="50">
+        <van-field
+          style="--van-cell-value-font-size: 16px"
+          v-model="formData.phoneNumber"
+          placeholder="请输入手机号"
+          type="tel"
+          size="large"
+          :rules="[{ required: true, message: '请输入手机号' }]"
+        >
+          <template #label>
+            <div @click="countryCodeOption.show = true">+{{ countryCode }}</div>
+          </template>
+        </van-field>
+        <van-field
+          v-model="formData.captchaCode"
+          placeholder="请输入图形证码"
+          type="tel"
+          maxlength="4"
+          style="--van-cell-value-font-size: 16px"
+          size="large"
+          :rules="[{ required: true, message: '请输入图形证码' }]"
+        >
+          <template #button>
+            <div class="h-36 w-110">
+              <img
+                v-if="captchaImage"
+                class="box-border w-full h-full"
+                :src="captchaImage"
+                fit="contain"
+                @click="getCaptchaInfo"
+              />
+            </div>
+          </template>
+        </van-field>
+        <van-field
+          v-model="formData.smsCode"
+          placeholder="请输入短信验证码"
+          type="tel"
+          maxlength="4"
+          size="large"
+          style="--van-cell-value-font-size: 16px"
+          :rules="[{ required: true, message: '请输入短信验证码' }]"
+        >
+          <template #button>
+            <div @click="handleGetSmsCode" class="text-primary text-base py-5">
+              {{ smsBtnText }}
+            </div>
+          </template>
+        </van-field>
+        <van-button
+          :disabled="isLoginBtnDisabled"
+          size="large"
+          style="background: #fa8446; margin-top: 30px"
+          color="#fff"
+          round
+          class="w-full"
+          @click="handleLogin"
+          :loading="isSubmiting"
+        >
+          登录</van-button
+        >
+      </van-form>
+    </div>
+
+    <van-popup v-model:show="countryCodeOption.show" position="bottom">
+      <div class="h-[600px] bg-white">
+        <van-index-bar>
+          <template v-for="item in Object.keys(countryCodeOption.listMap)">
+            <van-index-anchor :index="item" />
+            <van-cell
+              v-for="subItem in countryCodeOption.listMap[item]"
+              :key="subItem"
+              :title="`${subItem.country}(${subItem.countryCode})`"
+              @click="handleChangeCountryCode(subItem)"
+            />
+          </template>
+        </van-index-bar>
+      </div>
+    </van-popup>
+  </div>
+</template>
+
+<script setup>
+import { setIntervalImmediately } from "@/utils/index";
+
+definePageMeta({
+  layout: false,
+});
+
+const route = useRoute();
+
+let captchaUUID = "";
+const defatultSecond = 60;
+const countryCode = ref("86");
+const captchaImage = ref("");
+
+const formData = reactive({
+  phoneNumber: "",
+  captchaCode: "",
+  smsCode: "",
+});
+
+const smsCountDown = ref(defatultSecond);
+const isCountDown = computed(() => smsCountDown.value < defatultSecond);
+
+const smsBtnText = computed(() => {
+  if (isCountDown.value) {
+    return `重新获取(${smsCountDown.value})`;
+  } else {
+    return "获取验证码";
+  }
+});
+const isLoginBtnDisabled = computed(() => {
+  return (
+    !formData.phoneNumber ||
+    formData.captchaCode.trim().length != 4 ||
+    formData.smsCode.trim().length != 4
+  );
+});
+
+async function getCaptchaInfo() {
+  const { data } = await request("/website/web/captchaImage");
+  captchaUUID = data.uuid;
+  captchaImage.value = `data:image/jpg;base64,${data.img}`;
+}
+
+async function handleGetSmsCode() {
+  if (isCountDown.value) return;
+  if (!formData.phoneNumber) {
+    showToast("请输入手机号");
+    return;
+  }
+  if (!formData.captchaCode) {
+    showToast("请输入图形验证码");
+    return;
+  }
+  try {
+    await request("/website/web/validateCaptchaAndSendSms", {
+      query: {
+        uuid: captchaUUID,
+        countryCode: countryCode.value,
+        code: formData.captchaCode,
+        phoneNumber: formData.phoneNumber,
+      },
+    });
+    startCountDown();
+  } catch (error) {}
+}
+
+function startCountDown() {
+  smsCountDown.value = defatultSecond;
+  const timer = setIntervalImmediately(() => {
+    smsCountDown.value--;
+    if (smsCountDown.value <= 0) {
+      smsCountDown.value = defatultSecond;
+      clearInterval(timer);
+    }
+  }, 1000);
+}
+
+const isSubmiting = ref(false);
+async function handleLogin() {
+  try {
+    isSubmiting.value;
+    const { data } = await request("/website/web/doLoginBySms", {
+      method: "post",
+      body: {
+        ...formData,
+        loginMoblie: formData.phoneNumber,
+        countryCode: countryCode.value,
+      },
+    });
+    useAuthStore().setToken(data.tokenData);
+    useUserInfoStore().getUserInfo();
+    showSuccessToast("登录成功");
+
+    await navigateTo({
+      path: route.query.redirect || "/",
+      query: route.query,
+      replace: true,
+    });
+  } finally {
+    isSubmiting.value = false;
+  }
+}
+
+// 选择国家
+const countryCodeOption = reactive({
+  show: false,
+  listMap: {},
+});
+async function getAllCountryCode() {
+  const { data } = await request("/website/web/list");
+  countryCodeOption.listMap = data;
+}
+
+function handleChangeCountryCode(country) {
+  console.log(country);
+  countryCodeOption.show = false;
+  countryCode.value = country.countryCode;
+}
+
+onMounted(() => {
+  getCaptchaInfo();
+  getAllCountryCode();
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 6 - 0
src/pages/note-create-start/index.vue

@@ -0,0 +1,6 @@
+<template>
+  <div>开始写游记</div>
+</template>
+
+<script setup></script>
+<style lang="scss" scoped></style>

+ 82 - 0
src/pages/profile/index/notes.vue

@@ -0,0 +1,82 @@
+<template>
+  <div ref="container" class="w-full h-[200vh] box-border pb-16 px-20 bg-[#F8F8F8]">
+    <van-sticky :offset-top="0" :container="container">
+      <ProfileNotesTabs :tabs="tabs"></ProfileNotesTabs>
+    </van-sticky>
+
+    <div class="w-full h-full">
+      <van-pull-refresh v-model="loading" @refresh="onRefresh">
+        <div v-if="tab === 'published'">
+          <ProfileNotesPublished />
+        </div>
+        <div v-else-if="tab === 'auditing'">
+          <ProfileNotesAuditing />
+        </div>
+        <div v-else-if="tab === 'rejected'">
+          <!-- <ProfileNotesRejected /> -->
+        </div>
+        <div v-else-if="tab === 'draft'">
+          <!-- <ProfileNotesDraft /> -->
+        </div>
+      </van-pull-refresh>
+    </div>
+  </div>
+</template>
+
+<script setup>
+const tabs = [
+  {
+    lable: '已发布',
+    name: 'published',
+    to: ''
+  },
+  {
+    lable: '审核中',
+    name: 'auditing',
+    to: ''
+  },
+  {
+    lable: '未通过',
+    name: 'rejected',
+    to: ''
+  },
+  {
+    lable: '草稿箱',
+    name: 'draft',
+    to: ''
+  }
+]
+
+const route = useRoute()
+const container = ref(null)
+const tab = useRouteQuery('tab')
+const { loading, setLoading } = useLoading()
+
+const onRefresh = () => {
+  setTimeout(() => {
+    try {
+      showToast('刷新成功')
+      loading.value = false
+    } catch (err) {
+      showToast('刷新失败')
+    }
+  }, 1000)
+}
+
+watch(
+  tab,
+  (val) => {
+    if (val) return
+    navigateTo({
+      path: route.fullPath,
+      query: {
+        tab: tabs[0].name
+      },
+      replace: true
+    })
+  },
+  { immediate: true }
+)
+</script>
+
+<style lang="scss" scoped></style>

+ 19 - 0
src/stores/useAuth.js

@@ -0,0 +1,19 @@
+import { skipHydrate } from 'pinia'
+import { useStorage } from '@vueuse/core'
+
+export const useAuthStore = defineStore('auth', () => {
+  const token = useStorage('token', null)
+
+  const hasToken = computed(() => Boolean(token.value))
+
+  const setToken = (val) => (token.value = val)
+
+  const cleanToken = () => (token.value = null)
+
+  return {
+    token: skipHydrate(token),
+    hasToken,
+    setToken,
+    cleanToken
+  }
+})

+ 27 - 23
src/stores/useTabbar.js

@@ -1,48 +1,52 @@
-import { defineStore } from "pinia";
+import { defineStore } from 'pinia'
 
-export const useTabbarStore = defineStore("tabbar", () => {
-  const index = ref(0);
+export const useTabbarStore = defineStore('tabbar', () => {
+  const index = ref(0)
 
   const tabbarList = [
     {
-      name: "首页",
-      path: "/",
+      name: '首页',
+      path: '/'
     },
     {
-      name: "境外旅游",
-      path: "/travel",
+      name: '境外旅游',
+      path: '/travel'
     },
     {
-      name: "出国劳务",
-      path: "/labour",
+      name: '出国劳务',
+      path: '/labour'
     },
-  ];
+    {
+      name: '写游记',
+      path: '/profile/notes?tab=published'
+    }
+  ]
 
   watch(index, async (val) => {
     tabbarList.forEach(async (item, i) => {
       if (i === val) {
         await navigateTo({
-          path: item.path,
-        });
-        return;
+          path: item.path
+        })
+        return
       }
-    });
-  });
+    })
+  })
 
-  const route = useRoute();
+  const route = useRoute()
   watch(
     () => route.path,
     (val) => {
-      const targetIndex = tabbarList.findIndex((item) => item.path === val);
-      index.value = targetIndex;
+      const targetIndex = tabbarList.findIndex((item) => item.path === val)
+      index.value = targetIndex
     },
     {
-      immediate: true,
+      immediate: true
     }
-  );
+  )
 
   return {
     tabbarList,
-    index,
-  };
-});
+    index
+  }
+})

+ 12 - 0
src/stores/useUserInfo.js

@@ -0,0 +1,12 @@
+export const useUserInfoStore = defineStore('userInfo', () => {
+  const userInfo = ref({})
+
+  async function getUserInfo() {
+    const { data } = await request('/website/tourism/user/view')
+    userInfo.value = data
+  }
+  return {
+    userInfo,
+    getUserInfo
+  }
+})

+ 10 - 0
src/utils/index.js

@@ -0,0 +1,10 @@
+const setIntervalImmediately = (fn, duration) => setInterval((() => (fn(), fn))(), duration)
+
+function formatImgSrc(srcArr) {
+  if (Array.isArray(srcArr) && srcArr.length > 0) {
+    return srcArr[0] ?? ''
+  }
+  return ''
+}
+
+export { setIntervalImmediately, formatImgSrc }

+ 14 - 17
src/utils/request.js

@@ -2,8 +2,9 @@
 
 export function request(url, options = {}) {
   const config = useRuntimeConfig();
-  // const authStore = useAuthStore()
-  // const { token } = storeToRefs(authStore)
+
+  const authStore = useAuthStore();
+
   const defatulOpts = {
     method: "get",
     baseURL: config.public.baseApi,
@@ -12,16 +13,10 @@ export function request(url, options = {}) {
       ...options.headers,
       "Content-Type": "application/json",
       // deviceType: config.public.deviceType,
-      // token: token.value ? JSON.parse(token.value) : ''
+      authorization: authStore.token,
     },
     onRequest({ options }) {
       if (options.method === "post") {
-        // const bodyJson = options.body ? JSON.stringify(options.body) : ''
-        // const timestamp = new Date().getTime()
-        // let sign = `yingdeweilai888${bodyJson}${timestamp}`
-        // sign = md5(sign).toUpperCase()
-        // options.headers.sign = sign
-        // options.headers.timestamp = timestamp
       }
     },
     onRequestError() {
@@ -71,20 +66,22 @@ const handleHttpError = (status) => {
 };
 
 const handleServerError = async (code, msg) => {
-  // const authStore = useAuthStore()
-  // if (code === 401) {
-  //   authStore.cleanToken()
-  //   await navigateTo({
-  //     replace: true
-  //   })
-  //   return
-  // }
+  if (code === "UNAUTHORIZED_LOGIN") {
+    const authStore = useAuthStore();
+    authStore.cleanToken();
+    // await navigateTo({
+    //   path: '/login',
+    //   replace: true
+    // })
+    return;
+  }
   if (msg) {
     showErrorMessage(msg);
   }
 };
 
 const showErrorMessage = (msg) => {
+  showToast(msg);
   // const { message } = createDiscreteApi(['message'])
   // if (process.server) return
   // const { message } = useMessage()

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio