Преглед изворни кода

personal profile update page

fengchang пре 1 година
родитељ
комит
d5c0bd486d

+ 2 - 0
hichina-main-front-mobile-first/package.json

@@ -19,7 +19,9 @@
     "quasar": "^2.6.0",
     "unhead": "^1.1.30",
     "vue": "^3.0.0",
+    "vue-image-crop-upload": "^3.0.3",
     "vue-router": "^4.0.0",
+    "vue3-country-region-select": "^1.0.0",
     "vuejs3-datepicker": "^1.0.19"
   },
   "devDependencies": {

+ 3 - 0
hichina-main-front-mobile-first/src/boot/globalMixin.js

@@ -1,4 +1,5 @@
 import { boot } from "quasar/wrappers";
+import vueCountryRegionSelect from "vue3-country-region-select";
 // "async" is optional;
 // more info on params: https://v2.quasar.dev/quasar-cli/boot-files
 export default boot(async (/* { app, router, ... } */ { app, router }) => {
@@ -7,6 +8,8 @@ export default boot(async (/* { app, router, ... } */ { app, router }) => {
     console.log("testGlobal2");
   };
 
+  app.use(vueCountryRegionSelect);
+
   const normalizeMultiImageUrl = (input) => {
     if (input.indexOf(",") > -1) {
       return input.split(",").shift();

+ 1 - 1
hichina-main-front-mobile-first/src/layouts/MainLayout.vue

@@ -100,7 +100,7 @@
                 <q-item clickable>
                   <q-item-section>My Content</q-item-section>
                 </q-item>
-                <q-item clickable>
+                <q-item clickable @click="goPage('/user-info')">
                   <q-item-section>Edit Profile</q-item-section>
                 </q-item>
                 <q-separator />

+ 296 - 0
hichina-main-front-mobile-first/src/pages/UserInfoPage.vue

@@ -0,0 +1,296 @@
+<template>
+  <q-page>
+    <div class="row">
+      <div class="col-md-2"></div>
+      <div class="q-px-md col-12 col-md-8">
+        <div class="q-pa-md">
+          <my-upload
+            field="imageFile"
+            :width="300"
+            :height="300"
+            :url="serviceBase + '/api/v1/image/upload'"
+            :params="upload_icon_params"
+            @crop-upload-success="cropUploadSuccess"
+            lang-type="en"
+            :withCredentials="true"
+            v-model="showImageUpload"
+            img-format="png"
+          ></my-upload>
+        </div>
+        <div class="row">
+          <div style="width: 200px">
+            <q-img :src="updatePackage.profileImageUrl" />
+          </div>
+          <div class="col q-px-md">
+            <div class="text-weight-bold text-h4">My Profile Image</div>
+            <q-btn
+              @click="showUpload"
+              round
+              color="secondary"
+              icon="cloud_upload"
+            />
+            <p class="q-py-md notice mt-16">
+              Support format of jpg.png.bmp, and Picture size is limited at 5M
+            </p>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-12 col-sm-6 col-md-5">
+            <q-input
+              outlined
+              v-model="updatePackage.username"
+              label="Username"
+            />
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-12 col-sm-6 col-md-5">
+            <q-input outlined v-model="updatePackage.email" label="Email" />
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-12 col-sm-6 col-md-5">
+            <q-input outlined v-model="updatePackage.phone" label="Phone" />
+          </div>
+        </div>
+        <div class="row q-py-md">
+          <div class="col-12 col-sm-6 col-md-5">
+            <div class="text-weight-bold">Nationality:</div>
+            <country-select
+              v-model="updatePackage.nationality"
+              :country="updatePackage.nationality"
+              topCountry="US"
+            />
+          </div>
+        </div>
+        <div class="row">
+          <q-btn
+            class="glossy"
+            @click="updateInfo"
+            color="primary"
+            label="Update"
+          />
+        </div>
+        <div
+          class="row"
+          style="min-height: 10px; border-bottom: 1px solid gray"
+        ></div>
+        <div class="row q-py-md">
+          <div class="text-weight-bold text-h5">Change my password</div>
+        </div>
+        <div class="row">
+          <div class="col-12 col-sm-6 col-md-5">
+            <q-input
+              outlined
+              type="password"
+              v-model="currentPass"
+              label="Current Pasword"
+            />
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-12 col-sm-6 col-md-5">
+            <q-input
+              outlined
+              type="password"
+              v-model="newPass"
+              label="New Pasword"
+            />
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-12 col-sm-6 col-md-5">
+            <q-input
+              outlined
+              type="password"
+              v-model="confirmPass"
+              label="Confirm Pasword"
+            />
+          </div>
+        </div>
+        <div class="row q-py-md">
+          <q-btn
+            class="glossy"
+            color="primary"
+            @click="updatePassword"
+            label="Update Password"
+          />
+        </div>
+      </div>
+      <div class="col-md-2"></div>
+    </div>
+  </q-page>
+</template>
+
+<script>
+import { ref, onMounted, getCurrentInstance } from "vue";
+import { useQuasar } from "quasar";
+import myUpload from "vue-image-crop-upload";
+import { api } from "boot/axios";
+export default {
+  name: "UserInfoPage",
+  components: {
+    "my-upload": myUpload,
+  },
+  setup() {
+    const instance = getCurrentInstance();
+    const app = getCurrentInstance().appContext.app;
+    const gp = app.config.globalProperties;
+    const $q = useQuasar();
+
+    const serviceBase = ref("");
+    const country = ref("");
+    const updatePackage = ref({});
+    const upload_icon_params = ref({ expectedType: "thumbnail" });
+    const showImageUpload = ref(false);
+    const currentPass = ref("");
+    const newPass = ref("");
+    const confirmPass = ref("");
+
+    function showUpload() {
+      showImageUpload.value = true;
+    }
+
+    function updateInfo() {
+      console.log(updatePackage.value);
+      api
+        .put("/api/v1/user/basicInfo", updatePackage.value)
+        .then((res) => {
+          console.log(res.data);
+          if (res.data.ok == true) {
+            gp.$generalNotify($q, true, "Succeed udpating basic info");
+          } else {
+            gp.$generalNotify($q, false, "Failed udpating basic info");
+          }
+        })
+        .catch((err) => {
+          gp.$generalNotify($q, false, "Fail creating order" + err);
+        });
+    }
+
+    function updatePassword() {
+      if (
+        currentPass.value == null ||
+        currentPass.value.length < 1 ||
+        newPass.value == null ||
+        newPass.value.length < 1
+      ) {
+        gp.$generalNotify($q, false, "Cannot left any password empty");
+        return;
+      }
+      if (newPass.value != confirmPass.value) {
+        gp.$generalNotify(
+          $q,
+          false,
+          "Confirm password not the same with new Password"
+        );
+        return;
+      }
+      var params = {};
+      params.oldPass = currentPass.value;
+      params.newPass = newPass.value;
+      api
+        .put("/api/v1/user/updatePass", params)
+        .then((res) => {
+          if (res.data.ok == true) {
+            gp.$generalNotify($q, true, "Succeed updating password");
+          } else {
+            gp.$generalNotify($q, false, res.data.message);
+          }
+        })
+        .catch((err) => {
+          gp.$generalNotify($q, false, "Fail updating password " + err);
+        });
+    }
+
+    function getServiceBase() {
+      api
+        .get("/api/public/service/backend-service")
+        .then(function (response) {
+          console.log("service base:");
+          console.log(response.data);
+          serviceBase.value = response.data;
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+    }
+    function updateMyProfileImage(url) {
+      var params = {};
+      params.param = url;
+      api
+        .post("/api/v1/user/update-profile-image", params)
+        .then((res) => {
+          gp.$generalNotify($q, true, "Succeed updating profile image");
+          updatePackage.value.profileImageUrl = url;
+        })
+        .catch((err) => {
+          gp.$generalNotify(
+            $q,
+            false,
+            "Fail updating user profile image" + err
+          );
+        });
+    }
+    function cropUploadSuccess(jsonData, field) {
+      var url = jsonData.data;
+      updateMyProfileImage(url);
+      gp.$generalNotify($q, true, "上传成功");
+      showImageUpload.value = false;
+    }
+    function whoami() {
+      api
+        .get("/api/v1/user/whoami")
+        .then(function (response) {
+          console.log("current user in user-info: " + response.data);
+        })
+        .catch(function (error) {
+          console.log("currently not logged in user-info: " + error);
+          gp.$goPage("/auth/login");
+        });
+    }
+    function getMyPrincipal() {
+      api
+        .get("/api/v1/user/mysecurityinfo")
+        .then(function (response) {
+          console.log("my security data:");
+          console.log(response.data.data);
+          if (response.data.ok == true) {
+            country.value = updatePackage.value.nationality;
+            updatePackage.value = response.data.data;
+            if (
+              updatePackage.value.profileImageUrl == null ||
+              updatePackage.value.profileImageUrl.length < 1
+            ) {
+              updatePackage.value.profileImageUrl =
+                "https://photoprism.hichinatravel.com/api/v1/t/07dac61cc5dfec34dd9358f37bd70ce32de68488/32mcf2k4/fit_2048";
+            }
+          } else {
+            gp.$generalNotify($q, false, response.data.message);
+          }
+        })
+        .catch(function (error) {
+          console.log(error);
+        });
+    }
+    onMounted(() => {
+      whoami();
+      getServiceBase();
+      getMyPrincipal();
+    });
+    return {
+      showImageUpload,
+      cropUploadSuccess,
+      upload_icon_params,
+      serviceBase,
+      showUpload,
+      updatePassword,
+      updatePackage,
+      currentPass,
+      newPass,
+      confirmPass,
+      updateInfo,
+    };
+  },
+};
+</script>

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

@@ -66,6 +66,11 @@ const routes = [
     component: () => import("layouts/MainLayout.vue"),
     children: [{ path: "", component: () => import("pages/ContactPage.vue") }],
   },
+  {
+    path: "/user-info",
+    component: () => import("layouts/MainLayout.vue"),
+    children: [{ path: "", component: () => import("pages/UserInfoPage.vue") }],
+  },
   {
     path: "/regsuccess",
     component: () => import("layouts/MainLayout.vue"),

+ 83 - 2
hichina-main-front-mobile-first/yarn.lock

@@ -1117,6 +1117,44 @@
   resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
   integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
 
+"@intlify/core-base@9.2.2":
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.2.2.tgz#5353369b05cc9fe35cab95fe20afeb8a4481f939"
+  integrity sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==
+  dependencies:
+    "@intlify/devtools-if" "9.2.2"
+    "@intlify/message-compiler" "9.2.2"
+    "@intlify/shared" "9.2.2"
+    "@intlify/vue-devtools" "9.2.2"
+
+"@intlify/devtools-if@9.2.2":
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/@intlify/devtools-if/-/devtools-if-9.2.2.tgz#b13d9ac4b4e2fe6d2e7daa556517a8061fe8bd39"
+  integrity sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==
+  dependencies:
+    "@intlify/shared" "9.2.2"
+
+"@intlify/message-compiler@9.2.2":
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.2.2.tgz#e42ab6939b8ae5b3d21faf6a44045667a18bba1c"
+  integrity sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==
+  dependencies:
+    "@intlify/shared" "9.2.2"
+    source-map "0.6.1"
+
+"@intlify/shared@9.2.2":
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.2.2.tgz#5011be9ca2b4ab86f8660739286e2707f9abb4a5"
+  integrity sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==
+
+"@intlify/vue-devtools@9.2.2":
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz#b95701556daf7ebb3a2d45aa3ae9e6415aed8317"
+  integrity sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==
+  dependencies:
+    "@intlify/core-base" "9.2.2"
+    "@intlify/shared" "9.2.2"
+
 "@jest/schemas@^29.4.3":
   version "29.4.3"
   resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
@@ -1653,7 +1691,7 @@
     "@vue/compiler-dom" "3.3.4"
     "@vue/shared" "3.3.4"
 
-"@vue/devtools-api@^6.5.0":
+"@vue/devtools-api@^6.2.1", "@vue/devtools-api@^6.5.0":
   version "6.5.0"
   resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
   integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
@@ -2078,6 +2116,14 @@ babel-plugin-polyfill-regenerator@^0.5.0:
   dependencies:
     "@babel/helper-define-polyfill-provider" "^0.4.0"
 
+babel-runtime@^6.11.6:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
 balanced-match@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -2501,6 +2547,11 @@ core-js-compat@^3.30.1, core-js-compat@^3.30.2, core-js-compat@^3.6.5:
   dependencies:
     browserslist "^4.21.5"
 
+core-js@^2.4.0:
+  version "2.6.12"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
+  integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
+
 core-js@^3.6.5:
   version "3.30.2"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.30.2.tgz#6528abfda65e5ad728143ea23f7a14f0dcf503fc"
@@ -5053,6 +5104,11 @@ regenerate@^1.4.2:
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
   integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
 
+regenerator-runtime@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
 regenerator-runtime@^0.13.11:
   version "0.13.11"
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
@@ -5424,7 +5480,7 @@ source-map-support@~0.5.20:
     buffer-from "^1.0.0"
     source-map "^0.6.0"
 
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0:
+source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
   integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@@ -5832,6 +5888,23 @@ vue-eslint-parser@^9.3.0:
     lodash "^4.17.21"
     semver "^7.3.6"
 
+vue-i18n@^9.0.0:
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.2.2.tgz#aeb49d9424923c77e0d6441e3f21dafcecd0e666"
+  integrity sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==
+  dependencies:
+    "@intlify/core-base" "9.2.2"
+    "@intlify/shared" "9.2.2"
+    "@intlify/vue-devtools" "9.2.2"
+    "@vue/devtools-api" "^6.2.1"
+
+vue-image-crop-upload@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/vue-image-crop-upload/-/vue-image-crop-upload-3.0.3.tgz#0183cf8ebee30c08afba09a6fcb0a8fcd395e236"
+  integrity sha512-VeBsU0oI1hXeCvdpnu19DM/r3KTlI8SUXTxsHsU4MhDXR0ahRziiL9tf4FbILGx+gRVNZhGbl32yuM6TiaGNhA==
+  dependencies:
+    babel-runtime "^6.11.6"
+
 vue-loader@17.0.1:
   version "17.0.1"
   resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-17.0.1.tgz#c0ee8875e0610a0c2d13ba9b4d50a9c8442e7a3a"
@@ -5856,6 +5929,14 @@ vue-style-loader@4.1.3:
     hash-sum "^1.0.2"
     loader-utils "^1.0.2"
 
+vue3-country-region-select@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/vue3-country-region-select/-/vue3-country-region-select-1.0.0.tgz#f2356d55bfc6892721e40e70f829949abb730cef"
+  integrity sha512-4sHzVqd2AExz8Ijo2npiHCM6X50iD8AN2rtBZGeZc6y/LG4yNLzDFImZDT3UjBaAUFNUqQ1HR5akcQ1jrIuy5g==
+  dependencies:
+    vue "^3.0.0"
+    vue-i18n "^9.0.0"
+
 vue@^3.0.0:
   version "3.3.4"
   resolved "https://registry.yarnpkg.com/vue/-/vue-3.3.4.tgz#8ed945d3873667df1d0fcf3b2463ada028f88bd6"