Przeglądaj źródła

'add:管理后台'

weieryang 1 rok temu
commit
735ec39988

+ 4 - 0
.browserslistrc

@@ -0,0 +1,4 @@
1
+> 1%
2
+last 2 versions
3
+not dead
4
+not ie 11

+ 1 - 0
.env

@@ -0,0 +1 @@
1
+

+ 4 - 0
.env.development

@@ -0,0 +1,4 @@
1
+# 请注意,所有的环境变量前需要加上VUE_APP_前缀,这是Vue CLI项目的要求
2
+
3
+# 设置API地址
4
+VUE_APP_BASE_API_URL=http://192.168.1.15:8100/

+ 2 - 0
.env.production

@@ -0,0 +1,2 @@
1
+# 设置API地址
2
+VUE_APP_BASE_API_URL=http://192.168.1.15:8100/

+ 23 - 0
.eslintrc.js

@@ -0,0 +1,23 @@
1
+module.exports = {
2
+  root: true,
3
+  env: {
4
+    node: true,
5
+  },
6
+  extends: [
7
+    "plugin:vue/vue3-essential",
8
+    "eslint:recommended",
9
+    "@vue/typescript/recommended",
10
+    "plugin:prettier/recommended",
11
+  ],
12
+  parserOptions: {
13
+    ecmaVersion: 2020,
14
+  },
15
+  
16
+  rules: {
17
+    "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
18
+    "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
19
+    "prettier/prettier": "off",
20
+    "vue/multi-word-component-names": "off",
21
+    "@typescript-eslint/no-explicit-any": ["off"]
22
+  },
23
+};

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
1
+.DS_Store
2
+node_modules
3
+/dist
4
+
5
+
6
+# local env files
7
+.env.local
8
+.env.*.local
9
+
10
+# Log files
11
+npm-debug.log*
12
+yarn-debug.log*
13
+yarn-error.log*
14
+pnpm-debug.log*
15
+
16
+# Editor directories and files
17
+.idea
18
+.vscode
19
+*.suo
20
+*.ntvs*
21
+*.njsproj
22
+*.sln
23
+*.sw?

+ 1 - 0
.npmrc

@@ -0,0 +1 @@
1
+shamefully-hoist=true

+ 3 - 0
.prettierrc

@@ -0,0 +1,3 @@
1
+{
2
+    "endOfLine": "auto"
3
+}

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
1
+# bjbyrd-website
2
+
3
+## Project setup
4
+```
5
+pnpm install
6
+```
7
+
8
+### Compiles and hot-reloads for development
9
+```
10
+pnpm run serve
11
+```
12
+
13
+### Compiles and minifies for production
14
+```
15
+pnpm run build
16
+```
17
+
18
+### Lints and fixes files
19
+```
20
+pnpm run lint
21
+```
22
+
23
+### Customize configuration
24
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 3 - 0
babel.config.js

@@ -0,0 +1,3 @@
1
+module.exports = {
2
+  presets: ["@vue/cli-plugin-babel/preset"],
3
+};

+ 3 - 0
lint-staged.config.js

@@ -0,0 +1,3 @@
1
+module.exports = {
2
+  "*.{js,jsx,vue,ts,tsx}": "vue-cli-service lint",
3
+};

+ 39 - 0
package.json

@@ -0,0 +1,39 @@
1
+{
2
+  "name": "bjbyrd-website",
3
+  "version": "0.1.0",
4
+  "private": true,
5
+  "scripts": {
6
+    "serve": "vue-cli-service serve --mode development",
7
+    "build": "vue-cli-service build",
8
+    "lint": "vue-cli-service lint"
9
+  },
10
+  "dependencies": {
11
+    "axios": "^1.6.8",
12
+    "core-js": "^3.8.3",
13
+    "element-plus": "^2.6.2",
14
+    "vue": "^3.2.13",
15
+    "vue-router": "^4.0.3",
16
+    "vuex": "^4.0.0"
17
+  },
18
+  "devDependencies": {
19
+    "@typescript-eslint/eslint-plugin": "^5.4.0",
20
+    "@typescript-eslint/parser": "^5.4.0",
21
+    "@vue/cli-plugin-babel": "~5.0.0",
22
+    "@vue/cli-plugin-eslint": "~5.0.0",
23
+    "@vue/cli-plugin-router": "~5.0.0",
24
+    "@vue/cli-plugin-typescript": "~5.0.0",
25
+    "@vue/cli-plugin-vuex": "~5.0.0",
26
+    "@vue/cli-service": "~5.0.0",
27
+    "@vue/eslint-config-typescript": "^9.1.0",
28
+    "eslint": "^7.32.0",
29
+    "eslint-config-prettier": "^8.3.0",
30
+    "eslint-plugin-prettier": "^4.0.0",
31
+    "eslint-plugin-vue": "^8.0.3",
32
+    "lint-staged": "^11.1.2",
33
+    "prettier": "^2.4.1",
34
+    "typescript": "~4.5.5"
35
+  },
36
+  "gitHooks": {
37
+    "pre-commit": "lint-staged"
38
+  }
39
+}

Plik diff jest za duży
+ 7844 - 0
pnpm-lock.yaml


BIN
public/favicon.ico


+ 17 - 0
public/index.html

@@ -0,0 +1,17 @@
1
+<!DOCTYPE html>
2
+<html lang="">
3
+  <head>
4
+    <meta charset="utf-8">
5
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
8
+    <title><%= htmlWebpackPlugin.options.title %></title>
9
+  </head>
10
+  <body>
11
+    <noscript>
12
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
13
+    </noscript>
14
+    <div id="app"></div>
15
+    <!-- built files will be auto injected -->
16
+  </body>
17
+</html>

+ 31 - 0
src/App.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <!-- <nav>
3
+    <router-link to="/">Home</router-link> |
4
+    <router-link to="/about">About</router-link>
5
+  </nav> -->
6
+  <router-view />
7
+</template>
8
+
9
+<style>
10
+#app {
11
+  font-family: Avenir, Helvetica, Arial, sans-serif;
12
+  -webkit-font-smoothing: antialiased;
13
+  -moz-osx-font-smoothing: grayscale;
14
+  text-align: center;
15
+  color: #2c3e50;
16
+  height: 100%;
17
+}
18
+
19
+/* nav {
20
+  padding: 30px;
21
+}
22
+
23
+nav a {
24
+  font-weight: bold;
25
+  color: #2c3e50;
26
+}
27
+
28
+nav a.router-link-exact-active {
29
+  color: #42b983;
30
+} */
31
+</style>

BIN
src/assets/logo.png


+ 140 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,140 @@
1
+<template>
2
+  <div class="hello">
3
+    <h1>{{ msg }}</h1>
4
+    <p>
5
+      For a guide and recipes on how to configure / customize this project,<br />
6
+      check out the
7
+      <a href="https://cli.vuejs.org" target="_blank" rel="noopener"
8
+        >vue-cli documentation</a
9
+      >.
10
+    </p>
11
+    <h3>Installed CLI Plugins</h3>
12
+    <ul>
13
+      <li>
14
+        <a
15
+          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
16
+          target="_blank"
17
+          rel="noopener"
18
+          >babel</a
19
+        >
20
+      </li>
21
+      <li>
22
+        <a
23
+          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router"
24
+          target="_blank"
25
+          rel="noopener"
26
+          >router</a
27
+        >
28
+      </li>
29
+      <li>
30
+        <a
31
+          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex"
32
+          target="_blank"
33
+          rel="noopener"
34
+          >vuex</a
35
+        >
36
+      </li>
37
+      <li>
38
+        <a
39
+          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
40
+          target="_blank"
41
+          rel="noopener"
42
+          >eslint</a
43
+        >
44
+      </li>
45
+      <li>
46
+        <a
47
+          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript"
48
+          target="_blank"
49
+          rel="noopener"
50
+          >typescript</a
51
+        >
52
+      </li>
53
+    </ul>
54
+    <h3>Essential Links</h3>
55
+    <ul>
56
+      <li>
57
+        <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
58
+      </li>
59
+      <li>
60
+        <a href="https://forum.vuejs.org" target="_blank" rel="noopener"
61
+          >Forum</a
62
+        >
63
+      </li>
64
+      <li>
65
+        <a href="https://chat.vuejs.org" target="_blank" rel="noopener"
66
+          >Community Chat</a
67
+        >
68
+      </li>
69
+      <li>
70
+        <a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
71
+          >Twitter</a
72
+        >
73
+      </li>
74
+      <li>
75
+        <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
76
+      </li>
77
+    </ul>
78
+    <h3>Ecosystem</h3>
79
+    <ul>
80
+      <li>
81
+        <a href="https://router.vuejs.org" target="_blank" rel="noopener"
82
+          >vue-router</a
83
+        >
84
+      </li>
85
+      <li>
86
+        <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
87
+      </li>
88
+      <li>
89
+        <a
90
+          href="https://github.com/vuejs/vue-devtools#vue-devtools"
91
+          target="_blank"
92
+          rel="noopener"
93
+          >vue-devtools</a
94
+        >
95
+      </li>
96
+      <li>
97
+        <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
98
+          >vue-loader</a
99
+        >
100
+      </li>
101
+      <li>
102
+        <a
103
+          href="https://github.com/vuejs/awesome-vue"
104
+          target="_blank"
105
+          rel="noopener"
106
+          >awesome-vue</a
107
+        >
108
+      </li>
109
+    </ul>
110
+  </div>
111
+</template>
112
+
113
+<script lang="ts">
114
+import { defineComponent } from "vue";
115
+
116
+export default defineComponent({
117
+  name: "HelloWorld",
118
+  props: {
119
+    msg: String,
120
+  },
121
+});
122
+</script>
123
+
124
+<!-- Add "scoped" attribute to limit CSS to this component only -->
125
+<style scoped>
126
+h3 {
127
+  margin: 40px 0 0;
128
+}
129
+ul {
130
+  list-style-type: none;
131
+  padding: 0;
132
+}
133
+li {
134
+  display: inline-block;
135
+  margin: 0 10px;
136
+}
137
+a {
138
+  color: #42b983;
139
+}
140
+</style>

+ 56 - 0
src/components/layout/admin.vue

@@ -0,0 +1,56 @@
1
+<template>
2
+  <div class="common-layout" style="padding: 20px 100px;">
3
+    <el-container>
4
+      <el-header>
5
+        <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
6
+          <el-menu-item v-bind:key="index" :index="index" v-for="(item, index) in menus">{{ item.meta.title }}</el-menu-item>
7
+          <!-- <el-sub-menu index="2">
8
+            <template #title>Workspace</template>
9
+            <el-menu-item index="2-1">item one</el-menu-item>
10
+            <el-menu-item index="2-2">item two</el-menu-item>
11
+            <el-menu-item index="2-3">item three</el-menu-item>
12
+            <el-sub-menu index="2-4">
13
+              <template #title>item four</template>
14
+              <el-menu-item index="2-4-1">item one</el-menu-item>
15
+              <el-menu-item index="2-4-2">item two</el-menu-item>
16
+              <el-menu-item index="2-4-3">item three</el-menu-item>
17
+            </el-sub-menu>
18
+          </el-sub-menu>
19
+          <el-menu-item index="3" disabled>Info</el-menu-item>
20
+          <el-menu-item index="4">Orders</el-menu-item> -->
21
+        </el-menu>
22
+      </el-header>
23
+      <el-main style="padding: 20px;">
24
+        <!-- <el-breadcrumb separator="/">
25
+          <el-breadcrumb-item :to="{ path: '/' }">homepage</el-breadcrumb-item>
26
+          <el-breadcrumb-item><a href="/">promotion management</a></el-breadcrumb-item>
27
+          <el-breadcrumb-item>promotion list</el-breadcrumb-item>
28
+          <el-breadcrumb-item>promotion detail</el-breadcrumb-item>
29
+        </el-breadcrumb> -->
30
+        <el-scrollbar style="margin-top: 20px;">
31
+          <router-view />
32
+        </el-scrollbar>
33
+      </el-main>
34
+    </el-container>
35
+  </div>
36
+</template>
37
+<script lang="ts" setup>
38
+import { ref } from 'vue'
39
+import routers from "../../router";
40
+import { useRouter } from "vue-router";
41
+
42
+const menus = routers.options.routes.find((o) => { return o.name === 'admin'; }).children;
43
+
44
+
45
+
46
+const router = useRouter();
47
+console.log(router.currentRoute.value.path, 'router');
48
+const index = menus.findIndex((o) => { return o.path === router.currentRoute.value.path });
49
+const activeIndex = ref(index)
50
+const handleSelect = (key: string, keyPath: string[]) => {
51
+  console.log(key, keyPath)
52
+
53
+  activeIndex.value = Number(key);
54
+  router.push(menus[key])
55
+}
56
+</script>

+ 8 - 0
src/main.ts

@@ -0,0 +1,8 @@
1
+import { createApp } from "vue";
2
+import App from "./App.vue";
3
+import router from "./router";
4
+import store from "./store";
5
+import ElementPlus from 'element-plus'  // 引入Element Plus 所需
6
+import 'element-plus/dist/index.css'
7
+
8
+createApp(App).use(store).use(router).use(ElementPlus).mount("#app");

+ 65 - 0
src/router/index.ts

@@ -0,0 +1,65 @@
1
+import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
2
+import HomeView from "../views/HomeView.vue";
3
+import AdminLayout from "@/components/layout/admin.vue";
4
+
5
+const routes: Array<RouteRecordRaw> = [
6
+  {
7
+    path: "/",
8
+    name: "home",
9
+    component: HomeView,
10
+  },
11
+  {
12
+    path: "/about",
13
+    name: "about",
14
+    // route level code-splitting
15
+    // this generates a separate chunk (about.[hash].js) for this route
16
+    // which is lazy-loaded when the route is visited.
17
+    component: () =>
18
+      import(/* webpackChunkName: "about" */ "../views/AboutView.vue"),
19
+  },
20
+  {
21
+    path: "/admin",
22
+    component: AdminLayout,
23
+    name: 'admin',
24
+    redirect: "activity",
25
+    children: [
26
+      {
27
+        path: "/admin/activity",
28
+        component: () => import("@/views/admin/activity.vue"),
29
+        name: "AdminIndex",
30
+        meta: { title: "活动管理", icon: "dashboard", affix: true },
31
+      },
32
+      {
33
+        path: "/admin/company",
34
+        component: () => import("@/views/admin/company.vue"),
35
+        name: "AdminCompany",
36
+        meta: { title: "公司信息", icon: "dashboard", affix: true },
37
+      },
38
+      {
39
+        path: "/admin/product",
40
+        component: () => import("@/views/admin/product.vue"),
41
+        name: "AdminProduct",
42
+        meta: { title: "产品管理", icon: "dashboard", affix: true },
43
+      },
44
+      {
45
+        path: "/admin/article",
46
+        component: () => import("@/views/admin/article.vue"),
47
+        name: "AdminArticle",
48
+        meta: { title: "文章管理", icon: "dashboard", affix: true },
49
+      },
50
+      {
51
+        path: "/admin/artist",
52
+        component: () => import("@/views/admin/artist.vue"),
53
+        name: "AdminArtist",
54
+        meta: { title: "艺术家管理", icon: "dashboard", affix: true },
55
+      },
56
+    ],
57
+  },
58
+];
59
+
60
+const router = createRouter({
61
+  history: createWebHistory(process.env.BASE_URL),
62
+  routes,
63
+});
64
+
65
+export default router;

+ 6 - 0
src/shims-vue.d.ts

@@ -0,0 +1,6 @@
1
+/* eslint-disable */
2
+declare module '*.vue' {
3
+  import type { DefineComponent } from 'vue'
4
+  const component: DefineComponent<{}, {}, any>
5
+  export default component
6
+}

+ 9 - 0
src/store/index.ts

@@ -0,0 +1,9 @@
1
+import { createStore } from "vuex";
2
+
3
+export default createStore({
4
+  state: {},
5
+  getters: {},
6
+  mutations: {},
7
+  actions: {},
8
+  modules: {},
9
+});

+ 87 - 0
src/utils/request.ts

@@ -0,0 +1,87 @@
1
+import axios, {
2
+  AxiosError,
3
+  AxiosInstance,
4
+  AxiosResponse,
5
+  InternalAxiosRequestConfig,
6
+} from "axios";
7
+
8
+const config = {
9
+  baseURL: process.env.VUE_APP_BASE_API_URL,
10
+  timeout: 10000,
11
+  withCredentials: true,
12
+  headers: {},
13
+};
14
+
15
+class RequestHttp {
16
+  service: AxiosInstance;
17
+
18
+  constructor() {
19
+    this.service = axios.create(config);
20
+
21
+    /**
22
+     * @description 请求拦截器
23
+     */
24
+    this.service.interceptors.request.use(
25
+      (config: InternalAxiosRequestConfig) => {
26
+        return config;
27
+      }
28
+    );
29
+
30
+    /**
31
+     * @description 响应拦截器
32
+     */
33
+    this.service.interceptors.response.use(
34
+      (response: AxiosResponse) => {
35
+        const { data } = response;
36
+        return data;
37
+      },
38
+
39
+      (error: AxiosError) => {
40
+        const { response } = error;
41
+        if (response) {
42
+          checkStatus(response.status);
43
+        }
44
+        return false;
45
+      }
46
+    );
47
+  }
48
+
49
+  // 常用请求方法封装
50
+  get(url: string, params?: object, _object = {}) {
51
+    console.log(url, 'url');
52
+    return this.service.get(url, { params, ..._object });
53
+  }
54
+  post(url: string, params?: object, _object = {}) {
55
+    return this.service.post(url, params, _object);
56
+  }
57
+  put(url: string, params?: object, _object = {}) {
58
+    return this.service.put(url, params, _object);
59
+  }
60
+  delete(url: string, params?: object, _object = {}) {
61
+    return this.service.delete(url, { params, ..._object });
62
+  }
63
+}
64
+
65
+/**
66
+ * @description: 校验网络请求状态码
67
+ * @param {Number} status
68
+ * @return void
69
+ */
70
+ const checkStatus = (status: number): void => {
71
+  switch (status) {
72
+      case 404:
73
+          console.warn("资源不存在!");
74
+          break;
75
+      case 405:
76
+          console.warn("请求方式错误!");
77
+          break;
78
+      case 500:
79
+          console.warn("服务器异常!");
80
+          break;
81
+      default:
82
+          console.warn("请求失败!");
83
+  }
84
+};
85
+
86
+const request = new RequestHttp();
87
+export default request;

+ 5 - 0
src/views/AboutView.vue

@@ -0,0 +1,5 @@
1
+<template>
2
+  <div class="about">
3
+    <h1>This is an about page</h1>
4
+  </div>
5
+</template>

+ 18 - 0
src/views/HomeView.vue

@@ -0,0 +1,18 @@
1
+<template>
2
+  <div class="home">
3
+    <img alt="Vue logo" src="../assets/logo.png" />
4
+    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
5
+  </div>
6
+</template>
7
+
8
+<script lang="ts">
9
+import { defineComponent } from "vue";
10
+import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
11
+
12
+export default defineComponent({
13
+  name: "HomeView",
14
+  components: {
15
+    HelloWorld,
16
+  },
17
+});
18
+</script>

+ 276 - 0
src/views/admin/activity.vue

@@ -0,0 +1,276 @@
1
+<template>
2
+
3
+  <el-row>
4
+    <div>
5
+      <el-button @click="addInfo">添加活动</el-button>
6
+    </div>
7
+  </el-row>
8
+
9
+  <el-row>
10
+    <el-table :data="filterTableData" style="width: 100%">
11
+      <el-table-column label="活动" width="120">
12
+        <template #default="scope">
13
+          <el-image style="width: 100px; height: 50px" :src="baseApiUrl + scope.row.fileInfo[scope.row.file]"
14
+            :fit="'scale-down'" />
15
+        </template>
16
+      </el-table-column>
17
+      <el-table-column label="标题" prop="title" />
18
+      <el-table-column label="活动内容" prop="content" />
19
+      <el-table-column label="创建时间" prop="createTime" style="width: 100px;" />
20
+
21
+      <el-table-column align="right" style="width: 100px;">
22
+        <template #header>
23
+          <el-input v-model="search" size="small" placeholder="请输入标题" />
24
+        </template>
25
+        <template #default="scope">
26
+          <el-button size="small" @click="handleEdit(scope.row)">Edit</el-button>
27
+          <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">Delete</el-button>
28
+        </template>
29
+      </el-table-column>
30
+    </el-table>
31
+  </el-row>
32
+
33
+
34
+  <el-dialog v-model="centerDialogVisible" title="活动信息" width="500" center>
35
+
36
+    <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" class="demo-ruleForm"
37
+      :size="'default'" status-icon>
38
+      <el-form-item label="活动标题" prop="title">
39
+        <el-input v-model="ruleForm.title" />
40
+      </el-form-item>
41
+
42
+
43
+      <el-form-item label="活动内容" prop="content">
44
+        <el-input v-model="ruleForm.content" type="textarea" />
45
+      </el-form-item>
46
+
47
+      <el-form-item label="活动图片" prop="file">
48
+        <el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card"
49
+          :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeUploadSuccess" limit="1"
50
+          accept="image/*">
51
+          <el-icon>
52
+            <Plus />
53
+          </el-icon>
54
+        </el-upload>
55
+
56
+        <el-dialog v-model="dialogVisible">
57
+          <img w-full :src="dialogImageUrl" alt="Preview Image" />
58
+        </el-dialog>
59
+      </el-form-item>
60
+      <!-- <el-form-item label="Instant delivery" prop="delivery">
61
+        <el-switch v-model="ruleForm.delivery" />
62
+      </el-form-item> -->
63
+      <el-form-item>
64
+      </el-form-item>
65
+    </el-form>
66
+
67
+    <template #footer>
68
+      <div class="dialog-footer">
69
+        <el-button @click="centerDialogVisible = false">取消</el-button>
70
+        <el-button type="primary" @click="submitForm(ruleFormRef)">
71
+          提交
72
+        </el-button>
73
+      </div>
74
+    </template>
75
+  </el-dialog>
76
+</template>
77
+
78
+<script lang="ts" setup>
79
+import { onMounted, ref, computed, reactive } from 'vue'
80
+import request from '../../utils/request'
81
+import { Plus } from '@element-plus/icons-vue'
82
+
83
+import type { UploadProps, FormInstance } from 'element-plus'
84
+import { ElMessage, ElMessageBox } from 'element-plus'
85
+const baseApiUrl = process.env.VUE_APP_BASE_API_URL;
86
+
87
+const uploadUrl = baseApiUrl + '/system/accessories/upload'
88
+
89
+interface Acitvity {
90
+  id: number
91
+  title: string
92
+  content: string
93
+  file: string
94
+  fileInfo: object
95
+  topping: number
96
+  createTime: string
97
+}
98
+
99
+const centerDialogVisible = ref(false)
100
+let ruleForm = reactive<any>({
101
+  id: 0,
102
+  title: '',
103
+  content: '',
104
+  file: '',
105
+})
106
+const fileList = ref([] as Array<any>);
107
+const ruleFormRef = ref<FormInstance>()
108
+
109
+const rules = reactive<any>({
110
+  title: [
111
+    { required: true, message: '请输入标题', trigger: 'blur' },
112
+    { max: 15, message: '长度不能超过15', trigger: 'blur' },
113
+  ],
114
+  content: [
115
+    {
116
+      required: true,
117
+      message: '请输入内容',
118
+      trigger: 'blur',
119
+    },
120
+    { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
121
+  ],
122
+  file: [
123
+    {
124
+      type: 'array',
125
+      required: true,
126
+      message: '请上传图片',
127
+    },
128
+  ],
129
+})
130
+
131
+const handeUploadSuccess = (res: any) => {
132
+  console.log(res, 'res')
133
+  const { Id } = res.data;
134
+  if (Id) {
135
+    ruleForm.file = [Id]
136
+  }
137
+}
138
+
139
+const submitForm = async (formEl: FormInstance | undefined) => {
140
+  if (!formEl) return
141
+  const valRes = await formEl.validate((valid) => {
142
+    if (valid) {
143
+      return true;
144
+    } else {
145
+      return true;
146
+    }
147
+  })
148
+
149
+  if (!valRes) return;
150
+
151
+  // console.log(toRaw(ruleForm), 'ruleForm')
152
+
153
+  // 提交
154
+  let res: any;
155
+  if (ruleForm.id) {
156
+    res = await request.put('/Activity/activity', {
157
+      id: ruleForm.id,
158
+      title: ruleForm.title,
159
+      content: ruleForm.content,
160
+      file: ruleForm.file.join(',')
161
+    });
162
+  } else {
163
+    res = await request.post('/Activity/activity', {
164
+      title: ruleForm.title,
165
+      content: ruleForm.content,
166
+      file: ruleForm.file.join(',')
167
+    });
168
+  }
169
+
170
+  await alterRes(res);
171
+
172
+
173
+}
174
+
175
+const alterRes = async (res: any) => {
176
+  if (res.state === 'success') {
177
+    ElMessage({
178
+      message: '操作成功',
179
+      type: 'success',
180
+    })
181
+    await getList();
182
+    centerDialogVisible.value = false;
183
+  } else {
184
+    ElMessage({
185
+      message: res.message,
186
+      type: 'error',
187
+    })
188
+  }
189
+}
190
+
191
+const search = ref('')
192
+const filterTableData = computed(() =>
193
+  tableData.value.filter(
194
+    (data: any) =>
195
+      !search.value ||
196
+      data.title.toLowerCase().includes(search.value.toLowerCase())
197
+  )
198
+)
199
+
200
+const handleEdit = (row: Acitvity) => {
201
+  ruleForm.title = row.title;
202
+  ruleForm.content = row.content;
203
+  ruleForm.file = row.file.split(',');
204
+  ruleForm.id = row.id;
205
+  if (ruleForm.file) {
206
+    fileList.value.push({
207
+      name: row.id,
208
+      url: baseApiUrl + (row.fileInfo as any)[`${ruleForm.file}`],
209
+    });
210
+  }
211
+
212
+  centerDialogVisible.value = true;
213
+
214
+}
215
+const handleDelete = (id: number) => {
216
+  ElMessageBox.confirm(
217
+    '确定删除该活动吗?',
218
+    'Warning',
219
+    {
220
+      confirmButtonText: '确定',
221
+      cancelButtonText: '取消',
222
+      type: 'warning',
223
+    }
224
+  )
225
+    .then(async () => {
226
+
227
+      const res: any = await request.delete('/Activity/activity/' + id);
228
+
229
+      await alterRes(res);
230
+    });
231
+}
232
+
233
+let tableData = ref([]);
234
+
235
+const getList = async () => {
236
+  const res = await request.get('/Activity/activity');
237
+
238
+  if (res.data.length > 0) tableData.value = res.data;
239
+}
240
+
241
+onMounted(async () => {
242
+
243
+  await getList();
244
+})
245
+
246
+
247
+
248
+
249
+
250
+const handleRemove: UploadProps['onRemove'] = (uploadFile: any, uploadFiles: any) => {
251
+  console.log(uploadFile, uploadFiles)
252
+}
253
+
254
+const dialogImageUrl = ref('')
255
+const dialogVisible = ref(false)
256
+const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile: any) => {
257
+  dialogImageUrl.value = uploadFile.url!
258
+  dialogVisible.value = true
259
+}
260
+
261
+const addInfo = () => {
262
+  centerDialogVisible.value = true
263
+
264
+  // 
265
+  ruleForm = reactive<any>({
266
+    id: 0,
267
+    title: '',
268
+    content: '',
269
+    file: '',
270
+  });
271
+
272
+  fileList.value = [];
273
+
274
+}
275
+
276
+</script>

+ 332 - 0
src/views/admin/article.vue

@@ -0,0 +1,332 @@
1
+<template>
2
+
3
+  <el-row>
4
+    <div>
5
+      <el-button @click="addInfo">添加文章</el-button>
6
+    </div>
7
+  </el-row>
8
+
9
+  <el-row>
10
+    <el-table :data="filterTableData" style="width: 100%">
11
+      <el-table-column label="文章名称" prop="name" />
12
+      <el-table-column label="文章内容" prop="content" />
13
+      <!-- <el-table-column label="活动" width="120">
14
+        <template #default="scope">
15
+          <el-image style="width: 100px; height: 50px" :src="baseApiUrl + scope.row.fileInfo[scope.row.file]"
16
+            :fit="'scale-down'" />
17
+        </template>
18
+      </el-table-column> -->
19
+      
20
+      <el-table-column label="创建时间" prop="createTime" style="width: 100px;" />
21
+
22
+      <el-table-column align="right" style="width: 100px;">
23
+        <template #header>
24
+          <el-input v-model="search" size="small" placeholder="请输入标题" />
25
+        </template>
26
+        <template #default="scope">
27
+          <el-button size="small" @click="handleEdit(scope.row)">Edit</el-button>
28
+          <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">Delete</el-button>
29
+        </template>
30
+      </el-table-column>
31
+    </el-table>
32
+  </el-row>
33
+
34
+
35
+  <el-dialog v-model="centerDialogVisible" title="产品信息" width="500" center>
36
+
37
+    <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" class="demo-ruleForm"
38
+      :size="'default'" status-icon>
39
+      <el-form-item label="标题" prop="name">
40
+        <el-input v-model="ruleForm.name" />
41
+      </el-form-item>
42
+      <el-form-item label="内容" prop="content">
43
+        <el-input v-model="ruleForm.content" type="textarea" />
44
+      </el-form-item>
45
+
46
+      <el-form-item label="标题图片" prop="file">
47
+        <el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card"
48
+          :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeUploadSuccess" :limit="FILE_LIMIT"
49
+          accept="image/*">
50
+          <el-icon>
51
+            <Plus />
52
+          </el-icon>
53
+        </el-upload>
54
+
55
+        <el-dialog v-model="dialogVisible">
56
+          <img w-full :src="dialogImageUrl" alt="Preview Image" />
57
+        </el-dialog>
58
+      </el-form-item>
59
+
60
+
61
+      <el-form-item label="内容图片" prop="contentFile">
62
+        <el-upload v-model:file-list="typeFileList" :action="uploadUrl" list-type="picture-card"
63
+          :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeTypeUploadSuccess" :limit="CONTENT_FILE_LIMIT"
64
+          accept="image/*">
65
+          <el-icon>
66
+            <Plus />
67
+          </el-icon>
68
+        </el-upload>
69
+
70
+        <el-dialog v-model="dialogVisible">
71
+          <img w-full :src="dialogImageUrl" alt="Preview Image" />
72
+        </el-dialog>
73
+      </el-form-item>
74
+
75
+      <el-form-item>
76
+      </el-form-item>
77
+    </el-form>
78
+
79
+    <template #footer>
80
+      <div class="dialog-footer">
81
+        <el-button @click="centerDialogVisible = false">取消</el-button>
82
+        <el-button type="primary" @click="submitForm(ruleFormRef)">
83
+          提交
84
+        </el-button>
85
+      </div>
86
+    </template>
87
+  </el-dialog>
88
+</template>
89
+
90
+<script lang="ts" setup>
91
+import { onMounted, ref, computed, reactive, toRaw } from 'vue'
92
+import request from '../../utils/request'
93
+import { Plus } from '@element-plus/icons-vue'
94
+
95
+import type { UploadProps, FormInstance } from 'element-plus'
96
+import { ElMessage, ElMessageBox } from 'element-plus'
97
+const baseApiUrl = process.env.VUE_APP_BASE_API_URL;
98
+
99
+const uploadUrl = baseApiUrl + '/system/accessories/upload'
100
+
101
+const FILE_LIMIT = 6;
102
+const CONTENT_FILE_LIMIT = 1;
103
+
104
+
105
+let centerDialogVisible = ref(false)
106
+let ruleForm = reactive<any>({
107
+  id: 0,
108
+  name: '',
109
+  content: '',
110
+  file: [],
111
+  contentFile: [],
112
+})
113
+const fileList = ref([] as Array<any>);
114
+const typeFileList = ref([] as Array<any>);
115
+const ruleFormRef = ref<FormInstance>()
116
+
117
+const rules = reactive<any>({
118
+  name: [
119
+    { required: true, message: '请输入信息', trigger: 'blur' },
120
+    { max: 15, message: '长度不能超过15', trigger: 'blur' },
121
+  ],
122
+  content: [
123
+    {
124
+      required: true,
125
+      message: '请输入内容',
126
+      trigger: 'blur',
127
+    },
128
+    { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
129
+  ],
130
+  file: [
131
+    {
132
+      type: 'Array',
133
+      required: true,
134
+      message: '请上传图片',
135
+    },
136
+  ],
137
+  
138
+  contentFile: [
139
+    {
140
+      type: 'Array',
141
+      required: true,
142
+      message: '请上传图片',
143
+    },
144
+  ],
145
+})
146
+
147
+const handeUploadSuccess = (res: any, uploadFile: any) => {
148
+  const { Id } = res.data;
149
+  if (Id) {
150
+    ruleForm.file.push(Id);
151
+
152
+    uploadFile.uid = Id;
153
+    uploadFile.name = Id;
154
+    fileList.value[fileList.value.length -1] = uploadFile;
155
+  }
156
+}
157
+
158
+const handeTypeUploadSuccess = (res: any, uploadFile: any) => {
159
+  const { Id } = res.data;
160
+  if (Id) {
161
+    ruleForm.contentFile.push(Id);
162
+
163
+    uploadFile.uid = Id;
164
+    uploadFile.name = Id;
165
+    typeFileList.value[typeFileList.value.length -1] = uploadFile;
166
+  }
167
+}
168
+
169
+const submitForm = async (formEl: FormInstance | undefined) => {
170
+  if (!formEl) return
171
+  const valRes = await formEl.validate((valid) => {
172
+    if (valid) {
173
+      return true;
174
+    } else {
175
+      return true;
176
+    }
177
+  })
178
+
179
+  if (!valRes) return;
180
+
181
+  // console.log(toRaw(ruleForm), 'ruleForm')
182
+
183
+  const params = toRaw(ruleForm);
184
+
185
+  params.file = params.file.join(',');
186
+  params.contentFile = params.contentFile.join(',');
187
+
188
+  // 提交
189
+  let res: any;
190
+  if (ruleForm.id) {
191
+    res = await request.put('/GwHome/gwhome', params);
192
+  } else {
193
+    delete params.id;
194
+    res = await request.post('/GwHome/gwhome', params);
195
+  }
196
+
197
+  await alterRes(res);
198
+
199
+
200
+}
201
+
202
+const alterRes = async (res: any) => {
203
+  if (res.state === 'success') {
204
+    ElMessage({
205
+      message: '操作成功',
206
+      type: 'success',
207
+    })
208
+    await getList();
209
+    centerDialogVisible.value = false;
210
+  } else {
211
+    ElMessage({
212
+      message: res.message,
213
+      type: 'error',
214
+    })
215
+  }
216
+}
217
+
218
+const search = ref('')
219
+const filterTableData = computed(() =>
220
+  tableData.value.filter(
221
+    (data: any) =>
222
+    !search.value ||
223
+          (data.name && data.name.toLowerCase().includes(search.value.toLowerCase()))
224
+  )
225
+)
226
+
227
+const handleEdit = (row: any) => {
228
+  ruleForm.name = row.name;
229
+  ruleForm.content = row.content;
230
+  ruleForm.file = row.file.split(',');
231
+  ruleForm.contentFile = row.contentFile.split(',');
232
+  ruleForm.id = row.id;
233
+  fileList.value = [];
234
+  typeFileList.value = [];
235
+  // console.log(toRaw(ruleForm).nameFile, 'ruleForm.nameFile')
236
+  if (ruleForm.file) {
237
+
238
+      toRaw(ruleForm).file.forEach((o: any) => {
239
+          fileList.value.push({
240
+              uid: o,
241
+              name: o,
242
+              url: baseApiUrl + (row.fileInfo as any)[`${o}`],
243
+          });
244
+      })
245
+    
246
+  }
247
+
248
+  if (ruleForm.contentFile) {
249
+      toRaw(ruleForm).contentFile.forEach((o: any) => {
250
+          typeFileList.value.push({
251
+              uid: o,
252
+              name: o,
253
+              url: baseApiUrl + (row.contentFileInfo as any)[`${o}`],
254
+          });
255
+      })
256
+  }
257
+
258
+
259
+  centerDialogVisible.value = true;
260
+
261
+}
262
+const handleDelete = (id: number) => {
263
+  ElMessageBox.confirm(
264
+    '确定删除该活动吗?',
265
+    'Warning',
266
+    {
267
+      confirmButtonText: '确定',
268
+      cancelButtonText: '取消',
269
+      type: 'warning',
270
+    }
271
+  )
272
+    .then(async () => {
273
+
274
+      const res: any = await request.delete('/GwHome/gwhome/' + id);
275
+
276
+      await alterRes(res);
277
+    });
278
+}
279
+
280
+let tableData = ref([]);
281
+
282
+const getList = async () => {
283
+  const res = await request.get('/GwHome/gwhome');
284
+
285
+  if (res.data.length > 0) tableData.value = res.data;
286
+}
287
+
288
+onMounted(async () => {
289
+
290
+  await getList();
291
+})
292
+
293
+
294
+const handleRemove: UploadProps['onRemove'] = (uploadFile: any, uploadFiles: any) => {
295
+  console.log(uploadFile, uploadFiles)
296
+
297
+  ruleForm.nameFile = ruleForm.nameFile.filter((o: string) => {
298
+      return o !== uploadFile.uid;
299
+  });
300
+
301
+  ruleForm.typeFile = ruleForm.typeFile.filter((o: string) => {
302
+      return o !== uploadFile.uid;
303
+  });
304
+}
305
+
306
+const dialogImageUrl = ref('')
307
+const dialogVisible = ref(false)
308
+const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile: any) => {
309
+  dialogImageUrl.value = uploadFile.url
310
+  dialogVisible.value = true
311
+}
312
+
313
+const addInfo = () => {
314
+  centerDialogVisible.value = true
315
+
316
+  // 
317
+  ruleForm = reactive<any>({
318
+    id: 0,
319
+    name: '',
320
+    content: '',
321
+    file: [],
322
+    contentFile: [],
323
+  })
324
+
325
+  fileList.value = [];
326
+
327
+  typeFileList.value = [];
328
+}
329
+
330
+
331
+
332
+</script>

+ 266 - 0
src/views/admin/artist.vue

@@ -0,0 +1,266 @@
1
+<template>
2
+
3
+    <el-row>
4
+      <div>
5
+        <el-button @click="addInfo">添加艺术家</el-button>
6
+      </div>
7
+    </el-row>
8
+  
9
+    <el-row>
10
+      <el-table :data="filterTableData" style="width: 100%">
11
+        <el-table-column label="艺术家" width="120">
12
+          <template #default="scope">
13
+            <el-image style="width: 100px; height: 50px" :src="baseApiUrl + scope.row.fileInfo[scope.row.file]"
14
+              :fit="'scale-down'" />
15
+          </template>
16
+        </el-table-column>
17
+        <el-table-column label="姓名" prop="name" />
18
+        <el-table-column label="简介" prop="content" />
19
+        <el-table-column label="创建时间" prop="createTime" style="width: 100px;" />
20
+  
21
+        <el-table-column align="right" style="width: 100px;">
22
+          <template #header>
23
+            <el-input v-model="search" size="small" placeholder="请输入标题" />
24
+          </template>
25
+          <template #default="scope">
26
+            <el-button size="small" @click="handleEdit(scope.row)">Edit</el-button>
27
+            <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">Delete</el-button>
28
+          </template>
29
+        </el-table-column>
30
+      </el-table>
31
+    </el-row>
32
+  
33
+  
34
+    <el-dialog v-model="centerDialogVisible" title="艺术家信息" width="500" center>
35
+  
36
+      <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" class="demo-ruleForm"
37
+        :size="'default'" status-icon>
38
+        <el-form-item label="姓名" prop="name">
39
+          <el-input v-model="ruleForm.name" />
40
+        </el-form-item>
41
+  
42
+  
43
+        <el-form-item label="简介" prop="content">
44
+          <el-input v-model="ruleForm.content" type="textarea" />
45
+        </el-form-item>
46
+  
47
+        <el-form-item label="艺术家" prop="file">
48
+          <el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card"
49
+            :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeUploadSuccess" limit="1"
50
+            accept="image/*">
51
+            <el-icon>
52
+              <Plus />
53
+            </el-icon>
54
+          </el-upload>
55
+  
56
+          <el-dialog v-model="dialogVisible">
57
+            <img w-full :src="dialogImageUrl" alt="Preview Image" />
58
+          </el-dialog>
59
+        </el-form-item>
60
+        <!-- <el-form-item label="Instant delivery" prop="delivery">
61
+          <el-switch v-model="ruleForm.delivery" />
62
+        </el-form-item> -->
63
+        <el-form-item>
64
+        </el-form-item>
65
+      </el-form>
66
+  
67
+      <template #footer>
68
+        <div class="dialog-footer">
69
+          <el-button @click="centerDialogVisible = false">取消</el-button>
70
+          <el-button type="primary" @click="submitForm(ruleFormRef)">
71
+            提交
72
+          </el-button>
73
+        </div>
74
+      </template>
75
+    </el-dialog>
76
+  </template>
77
+  
78
+  <script lang="ts" setup>
79
+  import { onMounted, ref, computed, reactive } from 'vue'
80
+  import request from '../../utils/request'
81
+  import { Plus } from '@element-plus/icons-vue'
82
+  
83
+  import type { UploadProps, FormInstance } from 'element-plus'
84
+  import { ElMessage, ElMessageBox } from 'element-plus'
85
+  const baseApiUrl = process.env.VUE_APP_BASE_API_URL;
86
+  
87
+  const uploadUrl = baseApiUrl + '/system/accessories/upload'
88
+  
89
+  
90
+  const centerDialogVisible = ref(false)
91
+  let ruleForm = reactive<any>({
92
+    id: 0,
93
+    name: '',
94
+    content: '',
95
+    file: [],
96
+  })
97
+  const fileList = ref([] as Array<any>);
98
+  const ruleFormRef = ref<FormInstance>()
99
+  
100
+  const rules = reactive<any>({
101
+    name: [
102
+      { required: true, message: '请输入姓名', trigger: 'blur' },
103
+      { max: 15, message: '长度不能超过15', trigger: 'blur' },
104
+    ],
105
+    content: [
106
+      {
107
+        required: true,
108
+        message: '请输入内容',
109
+        trigger: 'blur',
110
+      },
111
+      { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
112
+    ],
113
+    file: [
114
+      {
115
+        type: 'array',
116
+        required: true,
117
+        message: '请上传图片',
118
+      },
119
+    ],
120
+  })
121
+  
122
+  const handeUploadSuccess = (res: any) => {
123
+    console.log(res, 'res')
124
+    const { Id } = res.data;
125
+    if (Id) {
126
+      ruleForm.file = [Id]
127
+    }
128
+  }
129
+  
130
+  const submitForm = async (formEl: FormInstance | undefined) => {
131
+    if (!formEl) return
132
+    const valRes = await formEl.validate((valid) => {
133
+      if (valid) {
134
+        return true;
135
+      } else {
136
+        return true;
137
+      }
138
+    })
139
+  
140
+    if (!valRes) return;
141
+  
142
+    // console.log(toRaw(ruleForm), 'ruleForm')
143
+  
144
+    // 提交
145
+    let res: any;
146
+    if (ruleForm.id) {
147
+      res = await request.put('/Artist/artist', {
148
+        id: ruleForm.id,
149
+        name: ruleForm.name,
150
+        content: ruleForm.content,
151
+        file: ruleForm.file.join(',')
152
+      });
153
+    } else {
154
+      res = await request.post('/Artist/artist', {
155
+        name: ruleForm.name,
156
+        content: ruleForm.content,
157
+        file: ruleForm.file.join(',')
158
+      });
159
+    }
160
+  
161
+    await alterRes(res);
162
+  
163
+  
164
+  }
165
+  
166
+  const alterRes = async (res: any) => {
167
+    if (res.state === 'success') {
168
+      ElMessage({
169
+        message: '操作成功',
170
+        type: 'success',
171
+      })
172
+      await getList();
173
+      centerDialogVisible.value = false;
174
+    } else {
175
+      ElMessage({
176
+        message: res.message,
177
+        type: 'error',
178
+      })
179
+    }
180
+  }
181
+  
182
+  const search = ref('')
183
+  const filterTableData = computed(() =>
184
+    tableData.value.filter(
185
+      (data: any) =>
186
+        !search.value ||
187
+        data.name.toLowerCase().includes(search.value.toLowerCase())
188
+    )
189
+  )
190
+  
191
+  const handleEdit = (row: any) => {
192
+    ruleForm.name = row.name;
193
+    ruleForm.content = row.content;
194
+    ruleForm.file = row.file.split(',');
195
+    ruleForm.id = row.id;
196
+    if (ruleForm.file) {
197
+      fileList.value.push({
198
+        name: row.id,
199
+        url: baseApiUrl + (row.fileInfo as any)[`${ruleForm.file}`],
200
+      });
201
+    }
202
+  
203
+    centerDialogVisible.value = true;
204
+  
205
+  }
206
+  const handleDelete = (id: number) => {
207
+    ElMessageBox.confirm(
208
+      '确定删除该活动吗?',
209
+      'Warning',
210
+      {
211
+        confirmButtonText: '确定',
212
+        cancelButtonText: '取消',
213
+        type: 'warning',
214
+      }
215
+    )
216
+      .then(async () => {
217
+  
218
+        const res: any = await request.delete('/Artist/artist/' + id);
219
+  
220
+        await alterRes(res);
221
+      });
222
+  }
223
+  
224
+  let tableData = ref([]);
225
+  
226
+  const getList = async () => {
227
+    const res = await request.get('/Artist/artist');
228
+  
229
+    if (res.data.length > 0) tableData.value = res.data;
230
+  }
231
+  
232
+  onMounted(async () => {
233
+  
234
+    await getList();
235
+  })
236
+  
237
+  
238
+  
239
+  
240
+  
241
+  const handleRemove: UploadProps['onRemove'] = (uploadFile: any, uploadFiles: any) => {
242
+    console.log(uploadFile, uploadFiles)
243
+  }
244
+  
245
+  const dialogImageUrl = ref('')
246
+  const dialogVisible = ref(false)
247
+  const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile: any) => {
248
+    dialogImageUrl.value = uploadFile.url!
249
+    dialogVisible.value = true
250
+  }
251
+  
252
+  const addInfo = () => {
253
+    centerDialogVisible.value = true
254
+  
255
+    // 
256
+    ruleForm = reactive<any>({
257
+      id: 0,
258
+      name: '',
259
+      content: '',
260
+      file: [],
261
+    })
262
+
263
+    fileList.value = [];
264
+  }
265
+  
266
+  </script>

+ 448 - 0
src/views/admin/company.vue

@@ -0,0 +1,448 @@
1
+<template>
2
+    <el-descriptions class="margin-top" title="公司简介" :column="3" :size="size" border>
3
+        <template #extra>
4
+            <el-button type="primary" @click="handleEdit">编辑</el-button>
5
+        </template>
6
+        <el-descriptions-item>
7
+            <template #label>
8
+                <div class="cell-item">
9
+                    <el-icon :style="iconStyle">
10
+                        <OfficeBuilding />
11
+                    </el-icon>
12
+                    公司名称
13
+                </div>
14
+            </template>
15
+            {{ companyInfo.name }}
16
+        </el-descriptions-item>
17
+        <el-descriptions-item>
18
+            <template #label>
19
+                <div class="cell-item">
20
+                    <el-icon :style="iconStyle">
21
+                        <iphone />
22
+                    </el-icon>
23
+                    联系电话
24
+                </div>
25
+            </template>
26
+            {{ companyInfo.tel }}
27
+        </el-descriptions-item>
28
+        <el-descriptions-item>
29
+            <template #label>
30
+                <div class="cell-item">
31
+                    <el-icon :style="iconStyle">
32
+                        <user />
33
+                    </el-icon>
34
+                    联系人
35
+                </div>
36
+            </template>
37
+            {{ companyInfo.contacts }}
38
+        </el-descriptions-item>
39
+        <el-descriptions-item>
40
+            <template #label>
41
+                <div class="cell-item">
42
+                    <el-icon :style="iconStyle">
43
+                        <Message />
44
+                    </el-icon>
45
+                    邮箱
46
+                </div>
47
+            </template>
48
+            {{ companyInfo.mailbox }}
49
+        </el-descriptions-item>
50
+        <el-descriptions-item :span="3">
51
+            <template #label>
52
+                <div class="cell-item">
53
+                    <el-icon :style="iconStyle">
54
+                        <Location />
55
+                    </el-icon>
56
+                    公司地址
57
+                </div>
58
+            </template>
59
+            {{ companyInfo.address }}
60
+        </el-descriptions-item>
61
+        <el-descriptions-item :span="6">
62
+            <template #label>
63
+                <div class="cell-item">
64
+                    <el-icon :style="iconStyle">
65
+                        <Document />
66
+                    </el-icon>
67
+                    公司简介
68
+                </div>
69
+            </template>
70
+            {{ companyInfo.content }}
71
+        </el-descriptions-item>
72
+        <el-descriptions-item>
73
+            <template #label>
74
+                <div class="cell-item">
75
+                    <el-icon :style="iconStyle">
76
+                        <BrushFilled />
77
+                    </el-icon>
78
+                    售后信息
79
+                </div>
80
+            </template>
81
+            {{ companyInfo.afterSalesContent }}
82
+        </el-descriptions-item>
83
+
84
+    </el-descriptions>
85
+
86
+
87
+    <div class="demo-image__error">
88
+        <div class="block" v-if="companyInfo.file">
89
+            <span class="demonstration">公司图片</span>
90
+            <el-image :src="baseApiUrl + companyInfo.fileInfo[companyInfo.file]"/>
91
+        </div>
92
+        <div class="block" v-if="companyInfo.wxFile">
93
+            <span class="demonstration">售后二维码</span>
94
+            <el-image :src="baseApiUrl + companyInfo.wxFileInfo[companyInfo.wxFile]" style="width: 200px; height: 200px"/>
95
+        </div>
96
+    </div>
97
+
98
+    <el-dialog v-model="centerDialogVisible" title="公司信息" width="500" center>
99
+
100
+        <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" class="demo-ruleForm"
101
+            :size="'default'" status-icon>
102
+            <el-form-item label="公司名称" prop="name">
103
+                <el-input v-model="ruleForm.name" />
104
+            </el-form-item>
105
+            <el-form-item label="联系电话" prop="tel">
106
+                <el-input v-model="ruleForm.tel" />
107
+            </el-form-item>
108
+            <el-form-item label="联系人" prop="contacts">
109
+                <el-input v-model="ruleForm.contacts" />
110
+            </el-form-item>
111
+            <el-form-item label="邮箱" prop="mailbox">
112
+                <el-input v-model="ruleForm.mailbox" />
113
+            </el-form-item>
114
+            <el-form-item label="公司地址" prop="address">
115
+                <el-input v-model="ruleForm.address" />
116
+            </el-form-item>
117
+            <el-form-item label="公司简介" prop="content">
118
+                <el-input v-model="ruleForm.content" type="textarea" />
119
+            </el-form-item>
120
+            <el-form-item label="售后信息" prop="afterSalesContent">
121
+                <el-input v-model="ruleForm.afterSalesContent" type="textarea" />
122
+            </el-form-item>
123
+
124
+            <el-form-item label="公司图片" prop="file">
125
+                <el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card"
126
+                    :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeUploadSuccess"
127
+                    limit="1" accept="image/*">
128
+                    <el-icon>
129
+                        <Plus />
130
+                    </el-icon>
131
+                </el-upload>
132
+
133
+                <el-dialog v-model="dialogVisible">
134
+                    <img w-full :src="dialogImageUrl" alt="Preview Image" />
135
+                </el-dialog>
136
+            </el-form-item>
137
+
138
+            <el-form-item label="售后二维码" prop="wxFile">
139
+                <el-upload v-model:file-list="wxFileList" :action="uploadUrl" list-type="picture-card"
140
+                    :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeWxUploadSuccess"
141
+                    limit="1" accept="image/*">
142
+                    <el-icon>
143
+                        <Plus />
144
+                    </el-icon>
145
+                </el-upload>
146
+
147
+                <el-dialog v-model="dialogVisible">
148
+                    <img w-full :src="dialogImageUrl" alt="Preview Image" />
149
+                </el-dialog>
150
+            </el-form-item>
151
+            <!-- <el-form-item label="Instant delivery" prop="delivery">
152
+    <el-switch v-model="ruleForm.delivery" />
153
+  </el-form-item> -->
154
+            <el-form-item>
155
+            </el-form-item>
156
+        </el-form>
157
+
158
+        <template #footer>
159
+            <div class="dialog-footer">
160
+                <el-button @click="centerDialogVisible = false">取消</el-button>
161
+                <el-button type="primary" @click="submitForm(ruleFormRef)">
162
+                    提交
163
+                </el-button>
164
+            </div>
165
+        </template>
166
+    </el-dialog>
167
+</template>
168
+
169
+<script setup lang="ts">
170
+import { computed, ref, reactive, onMounted, toRaw } from 'vue'
171
+import request from '../../utils/request'
172
+import { ElMessage } from 'element-plus'
173
+import {
174
+    Plus,
175
+    BrushFilled,
176
+    Document,
177
+    Message,
178
+    Iphone,
179
+    Location,
180
+    OfficeBuilding,
181
+    User,
182
+} from '@element-plus/icons-vue'
183
+import type { UploadProps, FormInstance } from 'element-plus'
184
+
185
+const baseApiUrl = process.env.VUE_APP_BASE_API_URL;
186
+
187
+const uploadUrl = baseApiUrl + '/system/accessories/upload'
188
+
189
+const size = ref('large')
190
+const iconStyle = computed(() => {
191
+    const marginMap: any = {
192
+        large: '8px',
193
+        default: '6px',
194
+        small: '4px',
195
+    }
196
+    return {
197
+        marginRight: marginMap[size.value] || marginMap.default,
198
+    }
199
+})
200
+
201
+const companyInfo = ref({} as any);
202
+
203
+const getInfo = async () => {
204
+    const res = await request.get('/Company/company');
205
+
206
+    if (res.data && res.data.length > 0) companyInfo.value = res.data[0];
207
+}
208
+
209
+onMounted(async () => {
210
+    await getInfo();
211
+});
212
+
213
+const centerDialogVisible = ref(false)
214
+const ruleForm = reactive<any>({
215
+  id: 0,
216
+  address: '',
217
+  afterSalesContent: '',
218
+  contacts: '',
219
+  content: '',
220
+  mailbox: '',
221
+  name: '',
222
+  tel: '',
223
+  wxFile: '',
224
+  file: '',
225
+})
226
+const fileList = ref([] as Array<any>);
227
+    const wxFileList = ref([] as Array<any>);
228
+const ruleFormRef = ref<FormInstance>()
229
+
230
+const rules = reactive<any>({
231
+name: [
232
+    { required: true, message: '请输入名称', trigger: 'blur' },
233
+    { max: 15, message: '长度不能超过15', trigger: 'blur' },
234
+  ],
235
+  contacts: [
236
+    { required: true, message: '请输入联系人', trigger: 'blur' },
237
+    { max: 4, message: '长度不能超过4', trigger: 'blur' },
238
+  ],
239
+  address: [
240
+    { required: true, message: '请输入地址', trigger: 'blur' },
241
+    { max: 100, message: '长度不能超过100', trigger: 'blur' },
242
+  ],
243
+  afterSalesContent: [
244
+    {
245
+      required: true,
246
+      message: '请输入内容',
247
+      trigger: 'blur',
248
+    },
249
+    { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
250
+  ],
251
+  tel: [
252
+  {
253
+      required: true,
254
+      message: '请输入联系电话',
255
+      trigger: 'blur',
256
+    },
257
+  ],
258
+  mailbox: [
259
+    {
260
+          required: true,
261
+          message: '请输入邮箱',
262
+          trigger: 'blur',
263
+        },
264
+        {
265
+          type: 'email',
266
+          message: '请输入正确的邮箱地址',
267
+          trigger: ['blur', 'change'],
268
+        },
269
+  ],
270
+  content: [
271
+    {
272
+      required: true,
273
+      message: '请输入内容',
274
+      trigger: 'blur',
275
+    },
276
+    { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
277
+  ],
278
+  file: [
279
+    {
280
+      required: true,
281
+      message: '请上传图片',
282
+    },
283
+  ],
284
+  wxFile: [
285
+    {
286
+      required: true,
287
+      message: '请上传图片',
288
+    },
289
+  ],
290
+})
291
+
292
+const handeUploadSuccess = (res: any) => {
293
+  console.log(res, 'res')
294
+  const { Id } = res.data;
295
+  if (Id) {
296
+    ruleForm.file = Id
297
+  }
298
+}
299
+
300
+const handeWxUploadSuccess = (res: any) => {
301
+  const { Id } = res.data;
302
+  if (Id) {
303
+    ruleForm.wxFile = Id
304
+  }
305
+}
306
+
307
+
308
+const submitForm = async (formEl: FormInstance | undefined) => {
309
+  if (!formEl) return
310
+  const valRes = await formEl.validate((valid) => {
311
+    if (valid) {
312
+      return true;
313
+    } else {
314
+      return true;
315
+    }
316
+  })
317
+
318
+  if (!valRes) return;
319
+
320
+  // console.log(toRaw(ruleForm), 'ruleForm')
321
+
322
+  // 提交
323
+  let res: any;
324
+  if (ruleForm.id) {
325
+    res = await request.put('/Company/company', toRaw(ruleForm));
326
+  } else {
327
+    res = await request.post('/Company/company', toRaw(ruleForm));
328
+  }
329
+
330
+  await alterRes(res);
331
+
332
+
333
+}
334
+
335
+const alterRes = async (res: any) => {
336
+  if (res.state === 'success') {
337
+    ElMessage({
338
+      message: '操作成功',
339
+      type: 'success',
340
+    })
341
+    await getInfo();
342
+    centerDialogVisible.value = false;
343
+  } else {
344
+    ElMessage({
345
+      message: res.message,
346
+      type: 'error',
347
+    })
348
+  }
349
+}
350
+
351
+const handleRemove: UploadProps['onRemove'] = (uploadFile: any, uploadFiles: any) => {
352
+  console.log(uploadFile, uploadFiles)
353
+}
354
+
355
+const dialogImageUrl = ref('')
356
+const dialogVisible = ref(false)
357
+const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile: any) => {
358
+  dialogImageUrl.value = uploadFile.url!
359
+  dialogVisible.value = true
360
+}
361
+
362
+
363
+const handleEdit = () => {
364
+
365
+  ruleForm.id = companyInfo.value.id;
366
+  ruleForm.address = companyInfo.value.address;
367
+  ruleForm.afterSalesContent= companyInfo.value.afterSalesContent;
368
+  ruleForm.contacts= companyInfo.value.contacts;
369
+  ruleForm.content= companyInfo.value.content;
370
+  ruleForm.mailbox= companyInfo.value.mailbox;
371
+  ruleForm.name= companyInfo.value.name;
372
+  ruleForm.tel= companyInfo.value.tel;
373
+  ruleForm.wxFile =companyInfo.value.wxFile;
374
+  ruleForm.file= companyInfo.value.file;
375
+  if (ruleForm.file) {
376
+    fileList.value = [{
377
+      name: ruleForm.file,
378
+      url: baseApiUrl + (companyInfo.value.fileInfo as any)[`${ruleForm.file}`],
379
+    }];
380
+  }
381
+
382
+  if (ruleForm.wxFile) {
383
+    wxFileList.value = [{
384
+      name: ruleForm.wxFile,
385
+      url: baseApiUrl + (companyInfo.value.wxFileInfo as any)[`${ruleForm.wxFile}`],
386
+    }];
387
+  }
388
+
389
+  centerDialogVisible.value = true;
390
+
391
+}
392
+
393
+</script>
394
+
395
+<style scoped>
396
+.el-descriptions {
397
+    margin-top: 20px;
398
+}
399
+
400
+.cell-item {
401
+    display: flex;
402
+    align-items: center;
403
+}
404
+
405
+.margin-top {
406
+    margin-top: 20px;
407
+}
408
+
409
+.demo-image__error {
410
+    margin-top: 20px
411
+}
412
+.demo-image__error .block {
413
+  padding: 30px 0;
414
+  text-align: center;
415
+  /* border-right: solid 1px var(--el-border-color); */
416
+  display: inline-block;
417
+  width: 49%;
418
+  box-sizing: border-box;
419
+  vertical-align: top;
420
+}
421
+.demo-image__error .demonstration {
422
+  display: block;
423
+  color: var(--el-text-color-secondary);
424
+  font-size: 14px;
425
+  margin-bottom: 20px;
426
+}
427
+.demo-image__error .el-image {
428
+  padding: 0 5px;
429
+  max-width: 300px;
430
+  max-height: 200px;
431
+  width: 100%;
432
+  height: 200px;
433
+}
434
+
435
+.demo-image__error .image-slot {
436
+  display: flex;
437
+  justify-content: center;
438
+  align-items: center;
439
+  width: 100%;
440
+  height: 100%;
441
+  background: var(--el-fill-color-light);
442
+  color: var(--el-text-color-secondary);
443
+  font-size: 30px;
444
+}
445
+.demo-image__error .image-slot .el-icon {
446
+  font-size: 30px;
447
+}
448
+</style>

+ 356 - 0
src/views/admin/product.vue

@@ -0,0 +1,356 @@
1
+<template>
2
+
3
+    <el-row>
4
+      <div>
5
+        <el-button @click="addInfo">添加产品</el-button>
6
+      </div>
7
+    </el-row>
8
+  
9
+    <el-row>
10
+      <el-table :data="filterTableData" style="width: 100%">
11
+        <el-table-column label="产品名称" prop="name" />
12
+        <el-table-column label="产品型号" prop="type" />
13
+        <!-- <el-table-column label="活动" width="120">
14
+          <template #default="scope">
15
+            <el-image style="width: 100px; height: 50px" :src="baseApiUrl + scope.row.fileInfo[scope.row.file]"
16
+              :fit="'scale-down'" />
17
+          </template>
18
+        </el-table-column> -->
19
+        
20
+        <el-table-column label="产品说明" prop="nameContent" />
21
+        <el-table-column label="型号说明" prop="typeContent" />
22
+        <el-table-column label="创建时间" prop="createTime" style="width: 100px;" />
23
+  
24
+        <el-table-column align="right" style="width: 100px;">
25
+          <template #header>
26
+            <el-input v-model="search" size="small" placeholder="请输入产品名称" />
27
+          </template>
28
+          <template #default="scope">
29
+            <el-button size="small" @click="handleEdit(scope.row)">Edit</el-button>
30
+            <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">Delete</el-button>
31
+          </template>
32
+        </el-table-column>
33
+      </el-table>
34
+    </el-row>
35
+  
36
+  
37
+    <el-dialog v-model="centerDialogVisible" title="产品信息" width="500" center>
38
+  
39
+      <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" class="demo-ruleForm"
40
+        :size="'default'" status-icon>
41
+        <el-form-item label="产品名称" prop="name">
42
+          <el-input v-model="ruleForm.name" />
43
+        </el-form-item>
44
+        <el-form-item label="产品说明" prop="nameContent">
45
+          <el-input v-model="ruleForm.nameContent" type="textarea" />
46
+        </el-form-item>
47
+
48
+        <el-form-item label="产品图片" prop="nameFile">
49
+          <el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card"
50
+            :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeUploadSuccess" limit="8"
51
+            accept="image/*">
52
+            <el-icon>
53
+              <Plus />
54
+            </el-icon>
55
+          </el-upload>
56
+  
57
+          <el-dialog v-model="dialogVisible">
58
+            <img w-full :src="dialogImageUrl" alt="Preview Image" />
59
+          </el-dialog>
60
+        </el-form-item>
61
+
62
+
63
+        <el-form-item label="型号名称" prop="type">
64
+          <el-input v-model="ruleForm.type" />
65
+        </el-form-item>
66
+        <el-form-item label="型号说明" prop="typeContent">
67
+          <el-input v-model="ruleForm.typeContent" type="textarea" />
68
+        </el-form-item>
69
+
70
+        <el-form-item label="型号图片" prop="typeFile">
71
+          <el-upload v-model:file-list="typeFileList" :action="uploadUrl" list-type="picture-card"
72
+            :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handeTypeUploadSuccess" limit="8"
73
+            accept="image/*">
74
+            <el-icon>
75
+              <Plus />
76
+            </el-icon>
77
+          </el-upload>
78
+  
79
+          <el-dialog v-model="dialogVisible">
80
+            <img w-full :src="dialogImageUrl" alt="Preview Image" />
81
+          </el-dialog>
82
+        </el-form-item>
83
+ 
84
+        <el-form-item>
85
+        </el-form-item>
86
+      </el-form>
87
+  
88
+      <template #footer>
89
+        <div class="dialog-footer">
90
+          <el-button @click="centerDialogVisible = false">取消</el-button>
91
+          <el-button type="primary" @click="submitForm(ruleFormRef)">
92
+            提交
93
+          </el-button>
94
+        </div>
95
+      </template>
96
+    </el-dialog>
97
+  </template>
98
+  
99
+  <script lang="ts" setup>
100
+  import { onMounted, ref, computed, reactive, toRaw } from 'vue'
101
+  import request from '../../utils/request'
102
+  import { Plus } from '@element-plus/icons-vue'
103
+  
104
+  import type { UploadProps, FormInstance } from 'element-plus'
105
+  import { ElMessage, ElMessageBox } from 'element-plus'
106
+  const baseApiUrl = process.env.VUE_APP_BASE_API_URL;
107
+  
108
+  const uploadUrl = baseApiUrl + '/system/accessories/upload'
109
+  
110
+  
111
+  const centerDialogVisible = ref(false)
112
+  let ruleForm = reactive<any>({
113
+    id: 0,
114
+    name: '',
115
+    nameContent: '',
116
+    nameFile: [],
117
+    type: '',
118
+    typeContent: '',
119
+    typeFile: [],
120
+  })
121
+  const fileList = ref([] as Array<any>);
122
+const typeFileList = ref([] as Array<any>);
123
+  const ruleFormRef = ref<FormInstance>()
124
+  
125
+  const rules = reactive<any>({
126
+    name: [
127
+      { required: true, message: '请输入信息', trigger: 'blur' },
128
+      { max: 15, message: '长度不能超过15', trigger: 'blur' },
129
+    ],
130
+    nameContent: [
131
+      {
132
+        required: true,
133
+        message: '请输入内容',
134
+        trigger: 'blur',
135
+      },
136
+      { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
137
+    ],
138
+    nameFile: [
139
+      {
140
+        type: 'Array',
141
+        required: true,
142
+        message: '请上传图片',
143
+      },
144
+    ],
145
+    type: [
146
+      { required: true, message: '请输入信息', trigger: 'blur' },
147
+      { max: 15, message: '长度不能超过15', trigger: 'blur' },
148
+    ],
149
+    typeContent: [
150
+      {
151
+        required: true,
152
+        message: '请输入内容',
153
+        trigger: 'blur',
154
+      },
155
+      { max: 1000, message: '长度不能超过1000', trigger: 'blur' },
156
+    ],
157
+    typeFile: [
158
+      {
159
+        type: 'Array',
160
+        required: true,
161
+        message: '请上传图片',
162
+      },
163
+    ],
164
+  })
165
+  
166
+  const handeUploadSuccess = (res: any, uploadFile: any) => {
167
+    const { Id } = res.data;
168
+    if (Id) {
169
+      ruleForm.nameFile.push(Id);
170
+
171
+      uploadFile.uid = Id;
172
+      uploadFile.name = Id;
173
+      fileList.value[fileList.value.length -1] = uploadFile;
174
+    }
175
+  }
176
+
177
+  const handeTypeUploadSuccess = (res: any, uploadFile: any) => {
178
+    const { Id } = res.data;
179
+    if (Id) {
180
+      ruleForm.typeFile.push(Id);
181
+
182
+      uploadFile.uid = Id;
183
+      uploadFile.name = Id;
184
+      typeFileList.value[typeFileList.value.length -1] = uploadFile;
185
+    }
186
+  }
187
+  
188
+  const submitForm = async (formEl: FormInstance | undefined) => {
189
+    if (!formEl) return
190
+    const valRes = await formEl.validate((valid) => {
191
+      if (valid) {
192
+        return true;
193
+      } else {
194
+        return true;
195
+      }
196
+    })
197
+  
198
+    if (!valRes) return;
199
+  
200
+    // console.log(toRaw(ruleForm), 'ruleForm')
201
+
202
+    const params = toRaw(ruleForm);
203
+
204
+    params.nameFile = params.nameFile.join(',');
205
+    params.typeFile = params.typeFile.join(',');
206
+  
207
+    // 提交
208
+    let res: any;
209
+    if (ruleForm.id) {
210
+      res = await request.put('/Product/product', params);
211
+    } else {
212
+      delete params.id;
213
+      res = await request.post('/Product/product', params);
214
+    }
215
+  
216
+    await alterRes(res);
217
+  
218
+  
219
+  }
220
+  
221
+  const alterRes = async (res: any) => {
222
+    if (res.state === 'success') {
223
+      ElMessage({
224
+        message: '操作成功',
225
+        type: 'success',
226
+      })
227
+      await getList();
228
+      centerDialogVisible.value = false;
229
+    } else {
230
+      ElMessage({
231
+        message: res.message,
232
+        type: 'error',
233
+      })
234
+    }
235
+  }
236
+  
237
+  const search = ref('')
238
+  const filterTableData = computed(() =>
239
+    tableData.value.filter(
240
+      (data: any) =>
241
+      !search.value ||
242
+            (data.name && data.name.toLowerCase().includes(search.value.toLowerCase()))
243
+    )
244
+  )
245
+  
246
+  const handleEdit = (row: any) => {
247
+    ruleForm.name = row.name;
248
+    ruleForm.nameContent = row.nameContent;
249
+    ruleForm.nameFile = row.nameFile.split(',');
250
+    ruleForm.type = row.type;
251
+    ruleForm.typeContent = row.typeContent;
252
+    ruleForm.typeFile = row.typeFile.split(',');
253
+    ruleForm.id = row.id;
254
+    fileList.value = [];
255
+    typeFileList.value = [];
256
+    console.log(toRaw(ruleForm).nameFile, 'ruleForm.nameFile')
257
+    if (ruleForm.nameFile) {
258
+
259
+        toRaw(ruleForm).nameFile.forEach((o: any) => {
260
+            fileList.value.push({
261
+                uid: o,
262
+                name: o,
263
+                url: baseApiUrl + (row.nameFileInfo as any)[`${o}`],
264
+            });
265
+        })
266
+      
267
+    }
268
+
269
+    if (ruleForm.typeFile) {
270
+        toRaw(ruleForm).typeFile.forEach((o: any) => {
271
+            typeFileList.value.push({
272
+                uid: o,
273
+                name: o,
274
+                url: baseApiUrl + (row.typeFileInfo as any)[`${o}`],
275
+            });
276
+        })
277
+    }
278
+  
279
+  
280
+    centerDialogVisible.value = true;
281
+  
282
+  }
283
+  const handleDelete = (id: number) => {
284
+    ElMessageBox.confirm(
285
+      '确定删除该活动吗?',
286
+      'Warning',
287
+      {
288
+        confirmButtonText: '确定',
289
+        cancelButtonText: '取消',
290
+        type: 'warning',
291
+      }
292
+    )
293
+      .then(async () => {
294
+  
295
+        const res: any = await request.delete('/Product/product/' + id);
296
+  
297
+        await alterRes(res);
298
+      });
299
+  }
300
+  
301
+  let tableData = ref([]);
302
+  
303
+  const getList = async () => {
304
+    const res = await request.get('/Product/product');
305
+  
306
+    if (res.data.length > 0) tableData.value = res.data;
307
+  }
308
+  
309
+  onMounted(async () => {
310
+  
311
+    await getList();
312
+  })
313
+  
314
+  
315
+  
316
+  
317
+  
318
+  const handleRemove: UploadProps['onRemove'] = (uploadFile: any, uploadFiles: any) => {
319
+    console.log(uploadFile, uploadFiles)
320
+
321
+    ruleForm.nameFile = ruleForm.nameFile.filter((o: string) => {
322
+        return o !== uploadFile.uid;
323
+    });
324
+
325
+    ruleForm.typeFile = ruleForm.typeFile.filter((o: string) => {
326
+        return o !== uploadFile.uid;
327
+    });
328
+  }
329
+  
330
+  const dialogImageUrl = ref('')
331
+  const dialogVisible = ref(false)
332
+  const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile: any) => {
333
+    dialogImageUrl.value = uploadFile.url
334
+    dialogVisible.value = true
335
+  }
336
+  
337
+  const addInfo = () => {
338
+    centerDialogVisible.value = true
339
+
340
+    // 
341
+    ruleForm = reactive<any>({
342
+        id: 0,
343
+        name: '',
344
+        nameContent: '',
345
+        nameFile: [],
346
+        type: '',
347
+        typeContent: '',
348
+        typeFile: [],
349
+    })
350
+
351
+    fileList.value = [];
352
+
353
+    typeFileList.value = [];
354
+}
355
+  
356
+  </script>

+ 40 - 0
tsconfig.json

@@ -0,0 +1,40 @@
1
+{
2
+  "compilerOptions": {
3
+    "target": "esnext",
4
+    "module": "esnext",
5
+    "strict": true,
6
+    "jsx": "preserve",
7
+    "moduleResolution": "node",
8
+    "skipLibCheck": true,
9
+    "esModuleInterop": true,
10
+    "allowSyntheticDefaultImports": true,
11
+    "forceConsistentCasingInFileNames": true,
12
+    "useDefineForClassFields": true,
13
+    "sourceMap": true,
14
+    "baseUrl": ".",
15
+    "types": [
16
+      "webpack-env"
17
+    ],
18
+    "paths": {
19
+      "@/*": [
20
+        "src/*"
21
+      ]
22
+    },
23
+    "lib": [
24
+      "esnext",
25
+      "dom",
26
+      "dom.iterable",
27
+      "scripthost"
28
+    ]
29
+  },
30
+  "include": [
31
+    "src/**/*.ts",
32
+    "src/**/*.tsx",
33
+    "src/**/*.vue",
34
+    "tests/**/*.ts",
35
+    "tests/**/*.tsx"
36
+  ],
37
+  "exclude": [
38
+    "node_modules"
39
+  ]
40
+}

+ 4 - 0
vue.config.js

@@ -0,0 +1,4 @@
1
+const { defineConfig } = require("@vue/cli-service");
2
+module.exports = defineConfig({
3
+  transpileDependencies: true,
4
+});