ソースを参照

blog edit and blog listing feature

fengchang 1 年間 前
コミット
00a77d23c3

+ 156 - 0
hichina-main-front-mobile-first/src/pages/BlogEditPage.vue

@@ -0,0 +1,156 @@
+<template>
+  <q-page>
+    <div class="row justify-center">
+      <div class="col-10">
+        <div class="col-12 q-mt-xl">
+          <q-input rounded outlined v-model="title" label="Blog title" />
+        </div>
+        <div class="col-12 q-mt-xl">
+          <QuillEditor
+            theme="snow"
+            v-model:content="content"
+            contentType="html"
+            toolbar="full"
+            :modules="combineModule"
+          />
+        </div>
+        <div class="col-12 q-mt-xl row q-mb-xl">
+          <div class="col-6 row justify-left">
+            <q-btn
+              @click="updateBlog()"
+              color="grey-4"
+              text-color="primary"
+              glossy
+              unelevated
+              icon="update"
+              label="Update"
+            />
+          </div>
+          <div class="col-6 row justify-left">
+            <q-btn
+              @click="goPage('/blog-detail/' + currentBlogId)"
+              color="grey-4"
+              text-color="primary"
+              glossy
+              unelevated
+              icon="visibility"
+              label="View Blog"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  </q-page>
+</template>
+
+<script>
+import { ref, onMounted, getCurrentInstance } from "vue";
+import { useQuasar } from "quasar";
+import { QuillEditor } from "@vueup/vue-quill";
+import "@vueup/vue-quill/dist/vue-quill.snow.css";
+import ImageUploader from "quill-image-uploader";
+import { api } from "boot/axios";
+import { useRoute } from "vue-router";
+export default {
+  name: "BlogEditPage",
+  components: {
+    QuillEditor,
+  },
+  setup() {
+    const instance = getCurrentInstance();
+    const app = getCurrentInstance().appContext.app;
+    const gp = app.config.globalProperties;
+    const $q = useQuasar();
+
+    const route = useRoute();
+
+    const title = ref("");
+    const content = ref("");
+
+    const currentBlogId = ref("");
+
+    currentBlogId.value = route.params.blogId;
+
+    const imageUploadModule = {
+      name: "imageUploader",
+      module: ImageUploader,
+      options: {
+        upload: (file) => {
+          return new Promise((resolve, reject) => {
+            const formData = new FormData();
+            formData.append("imageFile", file);
+            formData.append("expectedType", "blogImage");
+
+            api
+              .post("/api/v1/image/upload", formData)
+              .then((res) => {
+                resolve(res.data.data);
+              })
+              .catch((err) => {
+                reject("Upload failed");
+                console.error("Error:", err);
+              });
+          });
+        },
+      },
+    };
+
+    const combineModule = [imageUploadModule];
+
+    function whoami() {
+      api
+        .get("/api/v1/user/whoami")
+        .then(function (response) {
+          console.log("current user in setup: " + response.data);
+        })
+        .catch(function (error) {
+          console.log("currently not logged in setup: " + error);
+          gp.$goPage("/auth/login");
+        });
+    }
+
+    function loadBlogDetail(blogId) {
+      api
+        .get("/api/v1/blog/" + blogId)
+        .then(function (response) {
+          console.log("blog detail:");
+          console.log(response.data);
+          title.value = response.data.data.title;
+          content.value = response.data.data.content;
+        })
+        .catch(function (error) {
+          console.log("currently not logged in blog edit: " + error);
+        });
+    }
+    function updateBlog() {
+      const params = {};
+      params.title = title.value;
+      params.content = content.value;
+      params.headImageUrl = "";
+
+      api
+        .put("/api/v1/blog/edit-basic/" + route.params.blogId, params)
+        .then((res) => {
+          gp.$generalNotify($q, true, "Succeed updating blogs");
+        })
+        .catch((err) => {
+          console.error("Error:", err);
+          gp.$generalNotify($q, false, "Failed updating blogs");
+        });
+    }
+    onMounted(() => {
+      whoami();
+
+      loadBlogDetail(route.params.blogId);
+    });
+
+    return {
+      title,
+      content,
+      updateBlog,
+      currentBlogId,
+      combineModule,
+    };
+  },
+};
+</script>

+ 63 - 4
hichina-main-front-mobile-first/src/pages/MyBlogsPage.vue

@@ -1,5 +1,26 @@
 <template>
   <q-page>
+    <q-dialog v-model="confirmDelete" persistent>
+      <q-card>
+        <q-card-section class="row items-center">
+          <q-avatar icon="delete" color="primary" text-color="white" />
+          <span class="q-ml-sm"
+            >Are you sure you would like to delete this blog?.</span
+          >
+        </q-card-section>
+
+        <q-card-actions align="right">
+          <q-btn flat label="Cancel" color="primary" v-close-popup />
+          <q-btn
+            flat
+            label="Confirm Delete"
+            @click="deleteBLog"
+            color="primary"
+            v-close-popup
+          />
+        </q-card-actions>
+      </q-card>
+    </q-dialog>
     <div class="row justify-center">
       <div class="col-10 row">
         <div class="col-12 text-h5 q-pa-md text-weight-bold text-center">
@@ -22,13 +43,28 @@
               class="col-5 row no-wrap justify-center"
               style="border: 1px solid gray"
             >
-              <q-btn rounded dense color="primary" icon="edit" />
+              <q-btn
+                v-if="item.draft"
+                rounded
+                dense
+                color="primary"
+                label="Publish"
+                icon="publish"
+                @click="publishBlog(item.blogId)"
+              />
+              <q-btn
+                rounded
+                dense
+                color="primary"
+                icon="edit"
+                @click="goPage('/blog-edit/' + item.blogId)"
+              />
               <q-btn
                 rounded
                 dense
                 color="red"
                 icon="delete"
-                @click="deleteBLog(item.blogId)"
+                @click="confirmDeleteBlog(item.blogId)"
               />
             </div>
           </div>
@@ -58,10 +94,29 @@ export default {
     const totalCnt = ref(0);
     const totalPages = ref(1);
     const currentPage = ref(1);
+    const confirmDelete = ref(false);
+    const todeleteBlogID = ref("");
+
+    function publishBlog(blogId) {
+      api
+        .put("/api/v1/blog/publish/" + blogId)
+        .then((res) => {
+          gp.$generalNotify($q, true, "Succeed publishing blog");
+          loadMyBlogs();
+        })
+        .catch((err) => {
+          gp.$generalNotify($q, false, "Fail publishing blog" + err);
+        });
+    }
+
+    function confirmDeleteBlog(blogId) {
+      confirmDelete.value = true;
+      todeleteBlogID.value = blogId;
+    }
 
-    function deleteBLog(blogId) {
+    function deleteBLog() {
       api
-        .delete("/api/v1/blog/" + blogId)
+        .delete("/api/v1/blog/" + todeleteBlogID.value)
         .then((res) => {
           gp.$generalNotify($q, true, "Succeed deleting blog");
           loadMyBlogs();
@@ -122,7 +177,11 @@ export default {
       totalCnt,
       currentPage,
       totalPages,
+      confirmDelete,
+      todeleteBlogID,
       deleteBLog,
+      publishBlog,
+      confirmDeleteBlog,
     };
   },
 };

+ 5 - 0
hichina-main-front-mobile-first/src/router/routes.js

@@ -83,6 +83,11 @@ const routes = [
       { path: "", component: () => import("pages/BlogCreatePage.vue") },
     ],
   },
+  {
+    path: "/blog-edit/:blogId",
+    component: () => import("layouts/MainLayout.vue"),
+    children: [{ path: "", component: () => import("pages/BlogEditPage.vue") }],
+  },
   {
     path: "/regsuccess",
     component: () => import("layouts/MainLayout.vue"),