qinyan 1 year ago
parent
commit
3441321fde

+ 11 - 0
src/modules/module/auth/https.ts

@@ -0,0 +1,11 @@
+import { request } from "../../objects";
+
+export const https = {
+  passwordLogin(data: any) {
+    return request("/usercenter/login/password", { method: "POST", data });
+  },
+
+  queryUserInfo() {
+    return request("/usercenter/profile", { method: "GET" });
+  },
+};

+ 67 - 2
src/modules/module/auth/index.ts

@@ -1,11 +1,76 @@
+import loading from "@/components/Provider/Loading";
+import Modal from "@/components/Provider/Modal";
+import { ListController } from "@/controllers/ListController";
+import { request } from "@/modules/objects";
+import router from "@/views/admin/router";
+import { message } from "ant-design-vue";
 import { defineStore } from "pinia";
+import { https } from "./https";
 
 export const useAuth = defineStore("auth", {
   state: () => ({
-    userInfo: {},
+    userListController: new ListController(request),
+    userInfo: {} as any,
   }),
   getters: {},
   actions: {
-    initAuth() {},
+    async initAuth() {
+      this.userListController.setCrudPrefix("/usercenter/user");
+      this.queryUser();
+    },
+    async queryUser() {
+      const res = await https.queryUserInfo();
+      if (res.errorNo == 200) {
+        this.$state.userInfo = res.result.user;
+      } else {
+        localStorage.removeItem("token");
+        router.push("/login");
+      }
+    },
+
+    async passwordLogin(data: any) {
+      const res = await https.passwordLogin(data);
+      if (res.errorNo == 200) {
+        this.$state.userInfo = res.result.user;
+        localStorage.setItem("token", res.result.token);
+        router.push("/");
+      } else {
+        message.error(res.errorDesc);
+      }
+    },
+    logout() {
+      localStorage.removeItem("token");
+      router.push("/login");
+    },
+
+    async addOrUpdateUser(item: any) {
+      loading.show("保存中");
+      let res = {} as any;
+      if (item._id) {
+        res = await this.userListController.saveItem(item);
+      } else {
+        res = await this.userListController.addItem(item);
+      }
+      loading.hidden();
+      if (res.errorNo != 200) {
+        message.success(res.errorDesc);
+        return;
+      }
+      message.success("保存成功");
+    },
+
+    async deleteUser(item: any) {
+      const ok = await Modal.confirm({
+        title: "删除确认",
+        content: `删除后数据无法恢复,确认删除:${item?.name}?`,
+        type: "danger",
+      });
+      if (ok) {
+        loading.show("删除中");
+        await this.userListController.deleteItem(item._id);
+        loading.hidden();
+        message.success("删除成功");
+      }
+    },
   },
 });

+ 6 - 2
src/modules/objects/index.ts

@@ -1,10 +1,11 @@
 import { UploadController } from "@/controllers/UploadController";
 import { createRequest } from "@/utils/request";
-const token = localStorage.getItem("token");
+
 export const request = createRequest({
   baseURL: "https://www.infish.cn/adhuaxi/v1",
   interceptors: {
-    request(req: any) {
+    request: (req: any) => {
+      const token = localStorage.getItem("token");
       if (!req.headers) req.headers = {};
       req.headers["authorization"] = `Bearer ${token}`;
       return req;
@@ -12,7 +13,9 @@ export const request = createRequest({
     // response: (res: any) => {},
   },
 });
+
 export const uploader = new UploadController(request);
+
 export const renderTitle = (title?: string) => {
   if (title) {
     if (title.length > 30) {
@@ -22,6 +25,7 @@ export const renderTitle = (title?: string) => {
   }
   return "";
 };
+
 export const renderSummary = (summary?: string) => {
   if (summary) {
     if (summary.length >= 60) {

+ 10 - 4
src/utils/request.ts

@@ -11,10 +11,16 @@ export type RequestConfig = AxiosRequestConfig & {
 export function createRequest(defReqConfig: RequestConfig) {
   const { interceptors, ...httpConfig } = defReqConfig;
   const http = axios.create({ ...config, ...httpConfig });
-  Object.values(interceptors || {})?.forEach((item: any) => {
-    item.request && http.interceptors.request.use(item.request);
-    item.response && http.interceptors.response.use(item.response);
-  });
+
+  interceptors.request && http.interceptors.request.use(interceptors.request);
+  interceptors.response &&
+    http.interceptors.response.use(interceptors.response);
+
+  // Object.values(interceptors || {})?.forEach((item: any) => {
+  //   item.request && http.interceptors.request.use(item.request);
+  //   item.response && http.interceptors.response.use(item.response);
+  // });
+
   return async function (url: string, config: AxiosRequestConfig) {
     const thisConfig = Object.assign({}, config, { url });
 

+ 30 - 14
src/views/admin/components/Header.tsx

@@ -1,21 +1,37 @@
-import { css } from "@linaria/core";
+import { useAuth } from "@/modules";
+import { UserOutlined } from "@ant-design/icons-vue";
+import { Avatar, Dropdown, Menu } from "ant-design-vue";
 import { defineComponent } from "vue";
 
 export default defineComponent(() => {
+  const storeAuth = useAuth();
+
+  const handleClick = (data: any) => {
+    switch (data.key) {
+      case "logout":
+        storeAuth.logout();
+        break;
+    }
+  };
+
   return () => (
-    <div class={Header}>
-      <img src={getImageUrl("logo_footer.png")} />
-      后台管理系统
+    <div class="h-1/1 flex justify-between items-center text-light-50">
+      <div class="text-20px flex-1">
+        <img class="h-50px inline" src={getImageUrl("logo_footer.png")} />
+        <span class="ml-20px">后台管理系统</span>
+      </div>
+      <Dropdown
+        overlay={
+          <Menu onClick={handleClick}>
+            <Menu.Item key="logout">退出登录</Menu.Item>
+          </Menu>
+        }
+      >
+        <div class="flex items-center">
+          <Avatar icon={<UserOutlined />}></Avatar>
+          <span class="ml-10px leading-normal">{storeAuth.userInfo?.name}</span>
+        </div>
+      </Dropdown>
     </div>
   );
 });
-const Header = css`
-  img {
-    display: inline;
-    height: 50px;
-    object-fit: contain;
-    margin-right: 20px;
-  }
-  font-size: 20px;
-  color: #fff;
-`;

+ 3 - 0
src/views/admin/components/PageMenu.tsx

@@ -41,6 +41,9 @@ export default defineComponent({
           {categoryStore.categoryTree.map((item: any) => {
             return MenuRender(item);
           })}
+          <Menu.Item key={"/user"}>
+            <router-link to={"/user"}>用户管理</router-link>
+          </Menu.Item>
         </Menu>
       </div>
     );

+ 14 - 2
src/views/admin/login/index.tsx

@@ -1,3 +1,4 @@
+import { useAuth } from "@/modules";
 import { css } from "@linaria/core";
 import { Button, Form, Input } from "ant-design-vue";
 import { defineComponent, reactive } from "vue";
@@ -10,6 +11,8 @@ const tailLayout = {
 
 export default defineComponent({
   setup() {
+    const storeAuth = useAuth();
+
     const state = reactive({
       loading: false,
       loginType: "default",
@@ -41,7 +44,16 @@ export default defineComponent({
 
     const { validate, validateInfos } = Form.useForm(formState, rules);
 
-    async function submit() {}
+    async function submit() {
+      validate().then((data) => {
+        const params = {
+          password: data.password,
+          key: "usercenter",
+          phone: data.account,
+        };
+        storeAuth.passwordLogin(params);
+      });
+    }
 
     return () => (
       <div class={PageRoot}>
@@ -51,7 +63,7 @@ export default defineComponent({
           </div>
           <div class={"title"}>后台管理系统</div>
           <Form {...layout} name="basic">
-            <Form.Item name="phone" {...validateInfos.account}>
+            <Form.Item name="account" {...validateInfos.account}>
               <Input
                 placeholder="请输入账号"
                 v-model={[formState.account, "value"]}

+ 4 - 0
src/views/admin/router/index.ts

@@ -22,6 +22,10 @@ const router = createRouter({
           path: "/detail/:id",
           component: () => import("../detail"),
         },
+        {
+          path: "/user",
+          component: () => import("../user"),
+        },
       ],
     },
     {

+ 98 - 0
src/views/admin/user/components/OperationModal.tsx

@@ -0,0 +1,98 @@
+import Modal from "@/components/Provider/Modal";
+import { Button, Form, Input } from "ant-design-vue";
+import { defineComponent, reactive } from "vue";
+import { any } from "vue-types";
+
+const layout = {
+  labelCol: { span: 5 },
+  wrapperCol: { span: 18 },
+};
+
+export default defineComponent({
+  props: {
+    data: any(),
+  },
+  setup(props) {
+    const modal = Modal.use();
+
+    const formState: { [name: string]: any } = reactive({
+      loginName: "",
+      name: "",
+      phone: "",
+      password: "",
+      ...props.data,
+    });
+
+    const rules = reactive({
+      loginName: [
+        { required: true, message: "登录名不能为空", trigger: "change" },
+      ],
+      name: [{ required: true, message: "姓名不能为空", trigger: "change" }],
+      phone: [
+        { required: false, message: "手机号不能为空", trigger: "change" },
+      ],
+      password: [
+        {
+          required: props.data._id ? false : true,
+          message: "密码不能为空",
+          trigger: "change",
+        },
+        {
+          min: 6,
+          max: 18,
+          message: "密码长度为6~18位字符",
+          trigger: "change",
+        },
+      ],
+    });
+
+    const { validate, validateInfos } = Form.useForm(formState, rules);
+
+    function submit() {
+      validate().then(async () => {
+        modal.submit(formState);
+      });
+    }
+
+    return () => {
+      return (
+        <Form {...layout} onSubmit={submit}>
+          <Form.Item {...validateInfos.loginName} label="登录名">
+            <Input
+              disabled={props.data?._id ? true : false}
+              placeholder="请输入登录名"
+              v-model={[formState.loginName, "value"]}
+              maxlength={10}
+            />
+          </Form.Item>
+          <Form.Item {...validateInfos.name} label="姓名">
+            <Input
+              placeholder={"请输入姓名"}
+              v-model={[formState.name, "value"]}
+              maxlength={10}
+            />
+          </Form.Item>
+          <Form.Item {...validateInfos.phone} label="手机号">
+            <Input
+              placeholder="请输入手机号"
+              v-model={[formState.phone, "value"]}
+              maxlength={11}
+            />
+          </Form.Item>
+          <Form.Item {...validateInfos.password} label="密码">
+            <Input.Password
+              placeholder="请输入密码"
+              v-model={[formState.password, "value"]}
+              maxlength={10}
+            />
+          </Form.Item>
+          <Form.Item style={{ marginBottom: 0 }} wrapperCol={{ span: 24 }}>
+            <Button type="primary" htmlType="submit" block>
+              保存
+            </Button>
+          </Form.Item>
+        </Form>
+      );
+    };
+  },
+});

+ 112 - 0
src/views/admin/user/index.tsx

@@ -0,0 +1,112 @@
+import { Avatar, Button, Card, PageHeader, Space, Table } from "ant-design-vue";
+import { defineComponent, onMounted } from "vue";
+import { useRouter } from "vue-router";
+
+import loading from "@/components/Provider/Loading";
+import Modal from "@/components/Provider/Modal";
+import { useAuth } from "@/modules";
+import OperationModal from "./components/OperationModal";
+
+export default defineComponent({
+  setup() {
+    const router = useRouter();
+
+    const authStore = useAuth();
+
+    const columns = [
+      // {
+      //   title: "头像",
+      //   dataIndex: "avatar",
+      //   customRender: ({ text }: any) => {
+      //     return <Avatar src={text} />;
+      //   },
+      // },
+      {
+        title: "登录名",
+        dataIndex: "loginName",
+      },
+      {
+        title: "姓名",
+        dataIndex: "name",
+      },
+      {
+        title: "手机号",
+        dataIndex: "phone",
+        customRender: ({ text }: any) => <div>{text || "-"}</div>,
+      },
+      {
+        title: "操作",
+        dataIndex: "actions",
+        customRender: ({ record }: any) => {
+          const editDisabled =
+            record.loginName == "admin" &&
+            authStore.userInfo.loginName !== "admin";
+
+          const DeleteDisabled =
+            record.loginName == "admin" ||
+            record.loginName == authStore.userInfo.loginName;
+
+          return (
+            <Space>
+              <Button
+                disabled={editDisabled}
+                type="link"
+                onClick={() => showModal(record)}
+              >
+                编辑
+              </Button>
+              <Button
+                type="link"
+                danger
+                disabled={DeleteDisabled}
+                onClick={() => authStore.deleteUser(record)}
+              >
+                删除
+              </Button>
+            </Space>
+          );
+        },
+      },
+    ];
+
+    const initList = async () => {
+      loading.show("");
+      await authStore.userListController.loadPage(1);
+      loading.hidden();
+    };
+
+    const showModal = async (item?: any) => {
+      const itemData: any = await Modal.show(<OperationModal data={item} />, {
+        title: item._id ? `编辑用户` : `添加用户`,
+        width: "500px",
+      });
+      authStore.addOrUpdateUser(itemData);
+    };
+
+    onMounted(() => initList());
+
+    return () => (
+      <Card>
+        <PageHeader title="用户管理">
+          {{
+            extra: () => (
+              <Button type="primary" onClick={showModal}>
+                + 添加用户
+              </Button>
+            ),
+          }}
+        </PageHeader>
+        <Table
+          bordered
+          columns={columns}
+          dataSource={authStore.userListController.state.list}
+          pagination={{
+            pageSize: authStore.userListController.state.size,
+            total: authStore.userListController.state.total,
+            onChange: (v) => authStore.userListController.loadPage(v),
+          }}
+        />
+      </Card>
+    );
+  },
+});