yangg 1 bulan lalu
induk
melakukan
108787fc40
64 mengubah file dengan 2959 tambahan dan 145 penghapusan
  1. 101 0
      android/.gitignore
  2. 2 0
      android/app/.gitignore
  3. 54 0
      android/app/build.gradle
  4. 19 0
      android/app/capacitor.build.gradle
  5. 21 0
      android/app/proguard-rules.pro
  6. 26 0
      android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
  7. 41 0
      android/app/src/main/AndroidManifest.xml
  8. 5 0
      android/app/src/main/java/com/example/app/MainActivity.java
  9. TEMPAT SAMPAH
      android/app/src/main/res/drawable-land-hdpi/splash.png
  10. TEMPAT SAMPAH
      android/app/src/main/res/drawable-land-mdpi/splash.png
  11. TEMPAT SAMPAH
      android/app/src/main/res/drawable-land-xhdpi/splash.png
  12. TEMPAT SAMPAH
      android/app/src/main/res/drawable-land-xxhdpi/splash.png
  13. TEMPAT SAMPAH
      android/app/src/main/res/drawable-land-xxxhdpi/splash.png
  14. TEMPAT SAMPAH
      android/app/src/main/res/drawable-port-hdpi/splash.png
  15. TEMPAT SAMPAH
      android/app/src/main/res/drawable-port-mdpi/splash.png
  16. TEMPAT SAMPAH
      android/app/src/main/res/drawable-port-xhdpi/splash.png
  17. TEMPAT SAMPAH
      android/app/src/main/res/drawable-port-xxhdpi/splash.png
  18. TEMPAT SAMPAH
      android/app/src/main/res/drawable-port-xxxhdpi/splash.png
  19. 34 0
      android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  20. 170 0
      android/app/src/main/res/drawable/ic_launcher_background.xml
  21. TEMPAT SAMPAH
      android/app/src/main/res/drawable/splash.png
  22. 12 0
      android/app/src/main/res/layout/activity_main.xml
  23. 5 0
      android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  24. 5 0
      android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  25. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  26. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
  27. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  28. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  29. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
  30. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  31. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  32. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
  33. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  34. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  35. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
  36. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  37. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  38. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
  39. TEMPAT SAMPAH
      android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  40. 4 0
      android/app/src/main/res/values/ic_launcher_background.xml
  41. 7 0
      android/app/src/main/res/values/strings.xml
  42. 22 0
      android/app/src/main/res/values/styles.xml
  43. 5 0
      android/app/src/main/res/xml/file_paths.xml
  44. 18 0
      android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java
  45. 29 0
      android/build.gradle
  46. 3 0
      android/capacitor.settings.gradle
  47. 22 0
      android/gradle.properties
  48. TEMPAT SAMPAH
      android/gradle/wrapper/gradle-wrapper.jar
  49. 7 0
      android/gradle/wrapper/gradle-wrapper.properties
  50. 252 0
      android/gradlew
  51. 94 0
      android/gradlew.bat
  52. 5 0
      android/settings.gradle
  53. 16 0
      android/variables.gradle
  54. 9 0
      capacitor.config.ts
  55. 14 14
      electron-builder-simple.json
  56. 1006 20
      package-lock.json
  57. 5 1
      package.json
  58. 33 0
      scripts/clean.js
  59. TEMPAT SAMPAH
      src/assets/logos.JPG
  60. 8 0
      src/router/index.js
  61. 6 6
      src/views/index.vue
  62. 126 100
      src/views/xvue.vue
  63. 1 0
      vite.config.js
  64. 772 4
      yarn.lock

+ 101 - 0
android/.gitignore

@@ -0,0 +1,101 @@
+# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
+
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+#  Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
+
+# Cordova plugins for Capacitor
+capacitor-cordova-android-plugins
+
+# Copied web assets
+app/src/main/assets/public
+
+# Generated Config files
+app/src/main/assets/capacitor.config.json
+app/src/main/assets/capacitor.plugins.json
+app/src/main/res/xml/config.xml

+ 2 - 0
android/app/.gitignore

@@ -0,0 +1,2 @@
+/build/*
+!/build/.npmkeep

+ 54 - 0
android/app/build.gradle

@@ -0,0 +1,54 @@
+apply plugin: 'com.android.application'
+
+android {
+    namespace "com.example.app"
+    compileSdk rootProject.ext.compileSdkVersion
+    defaultConfig {
+        applicationId "com.example.app"
+        minSdkVersion rootProject.ext.minSdkVersion
+        targetSdkVersion rootProject.ext.targetSdkVersion
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        aaptOptions {
+             // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
+             // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
+            ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
+        }
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+repositories {
+    flatDir{
+        dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
+    }
+}
+
+dependencies {
+    implementation fileTree(include: ['*.jar'], dir: 'libs')
+    implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
+    implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
+    implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
+    implementation project(':capacitor-android')
+    testImplementation "junit:junit:$junitVersion"
+    androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
+    androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
+    implementation project(':capacitor-cordova-android-plugins')
+}
+
+apply from: 'capacitor.build.gradle'
+
+try {
+    def servicesJSON = file('google-services.json')
+    if (servicesJSON.text) {
+        apply plugin: 'com.google.gms.google-services'
+    }
+} catch(Exception e) {
+    logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
+}

+ 19 - 0
android/app/capacitor.build.gradle

@@ -0,0 +1,19 @@
+// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
+
+android {
+  compileOptions {
+      sourceCompatibility JavaVersion.VERSION_21
+      targetCompatibility JavaVersion.VERSION_21
+  }
+}
+
+apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
+dependencies {
+
+
+}
+
+
+if (hasProperty('postBuildExtras')) {
+  postBuildExtras()
+}

+ 21 - 0
android/app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 26 - 0
android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.getcapacitor.myapp;
+
+import static org.junit.Assert.*;
+
+import android.content.Context;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+
+    @Test
+    public void useAppContext() throws Exception {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        assertEquals("com.getcapacitor.app", appContext.getPackageName());
+    }
+}

+ 41 - 0
android/app/src/main/AndroidManifest.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+
+        <activity
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
+            android:name=".MainActivity"
+            android:label="@string/title_activity_main"
+            android:theme="@style/AppTheme.NoActionBarLaunch"
+            android:launchMode="singleTask"
+            android:exported="true">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+        </activity>
+
+        <provider
+            android:name="androidx.core.content.FileProvider"
+            android:authorities="${applicationId}.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths"></meta-data>
+        </provider>
+    </application>
+
+    <!-- Permissions -->
+
+    <uses-permission android:name="android.permission.INTERNET" />
+</manifest>

+ 5 - 0
android/app/src/main/java/com/example/app/MainActivity.java

@@ -0,0 +1,5 @@
+package com.example.app;
+
+import com.getcapacitor.BridgeActivity;
+
+public class MainActivity extends BridgeActivity {}

TEMPAT SAMPAH
android/app/src/main/res/drawable-land-hdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-land-mdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-land-xhdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-land-xxhdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-land-xxxhdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-port-hdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-port-mdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-port-xhdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-port-xxhdpi/splash.png


TEMPAT SAMPAH
android/app/src/main/res/drawable-port-xxxhdpi/splash.png


+ 34 - 0
android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml

@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeColor="#00000000"
+        android:strokeWidth="1">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeColor="#00000000"
+        android:strokeWidth="1" />
+</vector>

+ 170 - 0
android/app/src/main/res/drawable/ic_launcher_background.xml

@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportHeight="108"
+    android:viewportWidth="108">
+    <path
+        android:fillColor="#26A69A"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeColor="#33FFFFFF"
+        android:strokeWidth="0.8" />
+</vector>

TEMPAT SAMPAH
android/app/src/main/res/drawable/splash.png


+ 12 - 0
android/app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <WebView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</androidx.coordinatorlayout.widget.CoordinatorLayout>

+ 5 - 0
android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/ic_launcher_background"/>
+    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+</adaptive-icon>

+ 5 - 0
android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/ic_launcher_background"/>
+    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+</adaptive-icon>

TEMPAT SAMPAH
android/app/src/main/res/mipmap-hdpi/ic_launcher.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-mdpi/ic_launcher.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png


TEMPAT SAMPAH
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png


+ 4 - 0
android/app/src/main/res/values/ic_launcher_background.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="ic_launcher_background">#FFFFFF</color>
+</resources>

+ 7 - 0
android/app/src/main/res/values/strings.xml

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+    <string name="app_name">my-vue-app</string>
+    <string name="title_activity_main">my-vue-app</string>
+    <string name="package_name">com.example.app</string>
+    <string name="custom_url_scheme">com.example.app</string>
+</resources>

+ 22 - 0
android/app/src/main/res/values/styles.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+    <style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="android:background">@null</item>
+    </style>
+
+
+    <style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
+        <item name="android:background">@drawable/splash</item>
+    </style>
+</resources>

+ 5 - 0
android/app/src/main/res/xml/file_paths.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <external-path name="my_images" path="." />
+    <cache-path name="my_cache_images" path="." />
+</paths>

+ 18 - 0
android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java

@@ -0,0 +1,18 @@
+package com.getcapacitor.myapp;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+
+    @Test
+    public void addition_isCorrect() throws Exception {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 29 - 0
android/build.gradle

@@ -0,0 +1,29 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    
+    repositories {
+        google()
+        mavenCentral()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:8.5.0'
+        classpath 'com.google.gms:google-services:4.4.2'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+apply from: "variables.gradle"
+
+allprojects {
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 3 - 0
android/capacitor.settings.gradle

@@ -0,0 +1,3 @@
+// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
+include ':capacitor-android'
+project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')

+ 22 - 0
android/gradle.properties

@@ -0,0 +1,22 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true

TEMPAT SAMPAH
android/gradle/wrapper/gradle-wrapper.jar


+ 7 - 0
android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

+ 252 - 0
android/gradlew

@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"

+ 94 - 0
android/gradlew.bat

@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 5 - 0
android/settings.gradle

@@ -0,0 +1,5 @@
+include ':app'
+include ':capacitor-cordova-android-plugins'
+project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
+
+apply from: 'capacitor.settings.gradle'

+ 16 - 0
android/variables.gradle

@@ -0,0 +1,16 @@
+ext {
+    minSdkVersion = 23
+    compileSdkVersion = 35
+    targetSdkVersion = 35
+    androidxActivityVersion = '1.9.2'
+    androidxAppCompatVersion = '1.7.0'
+    androidxCoordinatorLayoutVersion = '1.2.0'
+    androidxCoreVersion = '1.15.0'
+    androidxFragmentVersion = '1.8.4'
+    coreSplashScreenVersion = '1.0.1'
+    androidxWebkitVersion = '1.12.1'
+    junitVersion = '4.13.2'
+    androidxJunitVersion = '1.2.1'
+    androidxEspressoCoreVersion = '3.6.1'
+    cordovaAndroidVersion = '10.1.1'
+}

+ 9 - 0
capacitor.config.ts

@@ -0,0 +1,9 @@
+import type { CapacitorConfig } from '@capacitor/cli';
+
+const config: CapacitorConfig = {
+  appId: 'com.example.app',
+  appName: 'my-vue-app',
+  webDir: 'dist'
+};
+
+export default config;

+ 14 - 14
electron-builder-simple.json

@@ -1,34 +1,34 @@
 {
-  "appId": "com.yourcompany.yourapp",
+  "appId": "com.your-app-name.app",
   "productName": "Your App Name",
   "directories": {
     "output": "electron-build"
   },
   "files": [
     "dist/**/*",
-    "electron/**/*.cjs",
-    "package.json"
+    "electron/**/*"
   ],
   "win": {
-    "icon": "public/icon.ico",
     "target": [
-      "portable"
-    ],
-    "extraResources": [
       {
-        "from": "resources/win/hideConsole.vbs",
-        "to": "hideConsole.vbs"
+        "target": "nsis",
+        "arch": [
+          "x64"
+        ]
       }
     ]
   },
-  "asar": false,
+  "nsis": {
+    "oneClick": false,
+    "allowToChangeInstallationDirectory": true,
+    "createDesktopShortcut": true,
+    "createStartMenuShortcut": true,
+    "shortcutName": "Your App Name"
+  },
+  "asar": true,
   "forceCodeSigning": false,
   "npmRebuild": false,
   "buildDependenciesFromSource": true,
-  "win": {
-    "target": ["portable"],
-    "icon": "public/icon.ico"
-  },
   "linux": {
     "target": ["AppImage"],
     "category": "Office"

File diff ditekan karena terlalu besar
+ 1006 - 20
package-lock.json


+ 5 - 1
package.json

@@ -12,10 +12,13 @@
     "electron:dev:direct": "vite build && electron . --direct-load",
     "electron:dev:force": "vite build && cross-env FORCE_DIRECT_LOAD=true electron .",
     "electron:dev:noconsole": "vite build && electron . --hide-console",
-    "electron:build": "rimraf electron-build && vite build && electron-builder --config electron-builder-simple.json"
+    "electron:build": "npm run clean && vite build && electron-builder --config electron-builder-simple.json --win --x64",
+    "clean": "node scripts/clean.js"
   },
   "dependencies": {
     "@ant-design/icons-vue": "^7.0.1",
+    "@capacitor/android": "^7.2.0",
+    "@capacitor/core": "^7.2.0",
     "ant-design-vue": "^4.2.6",
     "ant-design-x-vue": "^1.0.7",
     "axios": "^1.7.9",
@@ -32,6 +35,7 @@
     "vuex": "^4.0.2"
   },
   "devDependencies": {
+    "@capacitor/cli": "^7.2.0",
     "@vitejs/plugin-vue": "^5.2.1",
     "@vitejs/plugin-vue-jsx": "^4.1.1",
     "babel-plugin-import": "^1.13.8",

+ 33 - 0
scripts/clean.js

@@ -0,0 +1,33 @@
+const fs = require('fs');
+const path = require('path');
+
+function deleteFolderRecursive(directoryPath) {
+  if (fs.existsSync(directoryPath)) {
+    fs.readdirSync(directoryPath).forEach((file) => {
+      const curPath = path.join(directoryPath, file);
+      if (fs.lstatSync(curPath).isDirectory()) {
+        deleteFolderRecursive(curPath);
+      } else {
+        try {
+          fs.unlinkSync(curPath);
+        } catch (err) {
+          console.log(`无法删除文件 ${curPath}: ${err.message}`);
+        }
+      }
+    });
+    try {
+      fs.rmdirSync(directoryPath);
+    } catch (err) {
+      console.log(`无法删除目录 ${directoryPath}: ${err.message}`);
+    }
+  }
+}
+
+const buildDir = path.join(__dirname, '..', 'electron-build');
+try {
+  deleteFolderRecursive(buildDir);
+  console.log('清理完成');
+} catch (err) {
+  console.error('清理过程中发生错误:', err);
+  process.exit(1);
+} 

TEMPAT SAMPAH
src/assets/logos.JPG


+ 8 - 0
src/router/index.js

@@ -3,6 +3,7 @@ import { ROUTE } from './menu.js'
 
 // 使用命名的异步组件,便于调试
 const XVueComponent = () => import(/* webpackChunkName: "xvue" */ '@views/xvue.vue');
+const XVueLogin = () => import(/* webpackChunkName: "xvue" */ '@views/login.vue');
 
 const routes = [
   {
@@ -18,6 +19,13 @@ const routes = [
       },
     ]
   },
+  {
+    path: '/login',
+    name: 'login',
+    title: '登录',
+
+    component: XVueLogin
+  },
   // 添加一个简单的测试路由,用于验证路由系统是否正常工作
   {
     path: '/test',

+ 6 - 6
src/views/index.vue

@@ -220,7 +220,7 @@ const [ agent ] = useXAgent({
     
     try {
       // 调用多模态聊天接口
-      const apiUrl = `http://192.168.66.187:8082/chatbot/multimodal`;
+      const apiUrl = `http://121.36.251.245:8082/chatbot/multimodal`;
       const response = await fetch(apiUrl, {
         method: 'POST',
         headers: {
@@ -357,7 +357,7 @@ const onConversationClick: ConversationsProps['onActiveChange'] = async (key) =>
   // 这里可以添加加载特定会话消息的逻辑
   // 例如:
   try {
-    const response = await fetch(`http://192.168.66.187:8082/api/chat/messages?session_id=${key}`, {
+    const response = await fetch(`http://121.36.251.245:8082/api/chat/messages?session_id=${key}`, {
       method: 'GET',
       headers: {
         'Content-Type': 'application/json',
@@ -448,7 +448,7 @@ const uploadFile = async (file: File): Promise<string> => {
   formData.append('file', file);
   
   try {
-    const uploadResponse = await fetch('http://192.168.66.187:8082/upload/file', {
+    const uploadResponse = await fetch('http://121.36.251.245:8082/upload/file', {
       method: 'POST',
       body: formData,
     });
@@ -584,7 +584,7 @@ const senderHeader = computed(() => (
     }}
   >
     <Attachments
-      action="http://192.168.66.187:8082/upload/file" // 添加上传地址
+      action="http://121.36.251.245:8082/upload/file" // 添加上传地址
       name="file" // 指定上传字段名
       items={attachedFiles.value}
       onChange={handleFileChange}
@@ -666,7 +666,7 @@ const markdownStyles = `
 const fetchChatHistory = async () => {
   loadingHistory.value = true;
   try {
-    const response = await fetch('http://192.168.66.187:8082/api/chat/history', {
+    const response = await fetch('http://121.36.251.245:8082/api/chat/history', {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json',
@@ -742,7 +742,7 @@ const loadSessionMessages = async (sessionId: string) => {
     // 显示加载状态
     setMessages([{ id: 'loading', message: '加载消息中...', status: 'loading' }]);
     
-    const response = await fetch(`http://192.168.66.187:8082/api/chat/messages?session_id=${sessionId}`, {
+    const response = await fetch(`http://121.36.251.245:8082/api/chat/messages?session_id=${sessionId}`, {
       method: 'GET',
       headers: {
         'Content-Type': 'application/json',

+ 126 - 100
src/views/xvue.vue

@@ -3,14 +3,14 @@
     <!-- 左侧对话列表 -->
     <div class="sidebar">
       <div class="logo">
-        <img src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
+        <img src="../assets/logos.JPG"
           alt="logo" class="logo-img" />
-        <span class="logo-text">Ant Design X Vue</span>
+        <span class="logo-text">瑞赢旷世</span>
       </div>
 
       <Button @click="onAddConversation" type="link" class="new-chat-btn">
         <PlusOutlined />
-        New Conversation
+        新建会话
       </Button>
 
       <Conversations :items="conversationItems" :defaultActiveKey="activeConversation" :style="sidebarStyle"
@@ -55,7 +55,7 @@
           </template>
         </Welcome>
 
-        <Prompts v-if="placeholderPromptsItems.length" title="Do you want?" :items="placeholderPromptsItems"
+        <Prompts v-if="placeholderPromptsItems.length" title="你有什么问题?" :items="placeholderPromptsItems"
           :styles="promptsStyles" @itemClick="onPromptsItemClick" />
       </div>
       <!-- 底部输入区域 -->
@@ -131,30 +131,30 @@ const headerOpen = ref(false)
 const inputContent = ref('')
 const attachedFiles = ref([])
 const activeConversation = ref('')
-const API_BASE_URL = 'http://192.168.66.187:8082'
+const API_BASE_URL = 'http://192.168.100.187:8082'//'http://121.36.251.245:8082'
 // 对话列表数据
 const conversationItems = ref([
   {
     key: 'chat1',
-    label: 'What is Ant Design X?',
+    label: '当前窗口',
   }
 ])
 /* 对话列表菜单 */
 const menuConfig: ConversationsProps['menu'] = (conversation) => ({
   items: [
     {
-      label: 'Operation 1',
+      label: '操作 1',
       key: 'operation1',
       icon: h(EditOutlined),
     },
     {
-      label: 'Operation 2',
+      label: '操作 2',
       key: 'operation2',
       icon: h(StopOutlined),
       disabled: true,
     },
     {
-      label: 'Operation 3',
+      label: '操作 3',
       key: 'operation3',
       icon: h(DeleteOutlined),
       danger: true,
@@ -183,24 +183,24 @@ const roles = {
 const placeholderPromptsItems = ref([
   {
     key: '1',
-    label: 'Hot Topics',
-    icon: '',//markRaw(FireOutlined),
-    description: 'What are you interested in?',
+    label: '热门话题',
+    icon: '',
+    description: '你对什么感兴趣?',
     children: [
-      { key: '1-1', description: `What's new in X?` },
-      { key: '1-2', description: `What's AGI?` },
-      { key: '1-3', description: `Where is the doc?` },
+      { key: '1-1', description: 'X的新特性是什么?' },
+      { key: '1-2', description: '什么是AGI?' },
+      { key: '1-3', description: '在哪里可以找到文档?' },
     ],
   },
   {
-    key: '2',
-    label: 'Design Guide',
-    icon: '',//markRaw(ReadOutlined),
-    description: 'How to design a good product?',
+    key: '2', 
+    label: '设计指南',
+    icon: '',
+    description: '如何设计一个好产品?',
     children: [
-      { key: '2-1', icon: '', description: 'Know the well' },//markRaw(HeartOutlined)
-      { key: '2-2', icon: '', description: 'Set the AI role' },//markRaw(SmileOutlined)
-      { key: '2-3', icon: '', description: 'Express the feeling' },//markRaw(CommentOutlined)
+      { key: '2-1', icon: '', description: '了解基础' },
+      { key: '2-2', icon: '', description: '设置AI角色' },
+      { key: '2-3', icon: '', description: '表达感受' },
     ],
   },
 ])
@@ -208,13 +208,13 @@ const placeholderPromptsItems = ref([
 const senderPromptsItems = ref([
   {
     key: '1',
-    description: 'Hot Topics',
-    icon: ''//markRaw(FireOutlined),
+    description: '热门话题',
+    icon: ''
   },
   {
     key: '2',
-    description: 'Design Guide',
-    icon: '',//markRaw(ReadOutlined),
+    description: '设计指南', 
+    icon: ''
   },
 ])
 
@@ -242,22 +242,20 @@ const { messages, onRequest, setMessages } = useXChat({
     request: async ({ message, attachments }, { onSuccess, onError }) => {
       try {
         loading.value = true
-        console.log('messages', messages.value)
-        // 保存当前消息状态
-        const currentMessages = [...messages.value]
+        
+        // 保存发送请求前的消息状态
+        const previousMessages = [...messages.value]
         
         // 构建请求数据
         const formData = new FormData()
         formData.append('message', message)
 
-        // 添加附件
         if (attachments?.length) {
           attachments.forEach(file => {
             formData.append('files', file)
           })
         }
 
-        // 发送请求到后端API
         const response = await fetch('/api/chat', {
           method: 'POST',
           body: formData
@@ -268,9 +266,12 @@ const { messages, onRequest, setMessages } = useXChat({
         }
 
         const data = await response.json()
-        // 确保在成功回调前不会清空消息
-        setMessages(currentMessages)
-        onSuccess(data.message)
+        
+        // 在调用 onSuccess 之前,确保恢复之前的消息
+        nextTick(() => {
+          setMessages(previousMessages)
+          onSuccess(data.message)
+        })
 
       } catch (error) {
         onError(error)
@@ -280,9 +281,9 @@ const { messages, onRequest, setMessages } = useXChat({
       }
     }
   })[0],
-  initialMessages: [], // 添加初始空数组
-  // 添加配置以防止自动清空消息
-  preserveMessages: true
+  initialMessages: [],
+  preserveMessages: true,
+  clearOnRequest: false
 })
 
 // 添加消息状态监听
@@ -301,8 +302,8 @@ watch(messages, (newMessages) => {
 // 监听会话切换
 watch(activeConversation, () => {
   if (activeConversation.value !== undefined) {
-    // 切换会话时清空消息
-    setMessages([])
+    // 切换会话时清空消息 会导致第一条记录置空
+   /*  setMessages([]) */
   }
 }, { immediate: true })
 
@@ -524,27 +525,41 @@ const handleFocus = () => {
 // 修改消息处理部分
 const handleSubmit = async () => {
   const content = inputContent.value.trim()
-  if (!content && !items.value.length) return
+  if (!content && !items.value.length && imageUrls.value.length === 0 && documentUrls.value.length === 0) return
 
   try {
     loading.value = true
     const userMessageId = `user-${Date.now()}`
     
-    // 保存当前消息状态
-    const currentMessages = [...messages.value]
+    // 创建新的消息数组,包含用户消息
+    const newMessages = [
+      ...messages.value,
+      {
+        id: userMessageId,
+        role: 'local',
+        message: content,
+        status: 'success'
+      }
+    ]
     
-    // 添加用户消息
-    const newMessages = [...currentMessages, {
-      id: userMessageId,
-      role: 'local',
+    // 使用函数形式更新消息,确保获取最新状态
+    setMessages(() => newMessages)
+
+   
+    const requestData = {
       message: content,
-      status: 'success'
-    }]
+      chat_config_id: "17",
+      user_id: 4,
+      session_id: activeConversation.value,
+      source: "pc",
+      image_urls: imageUrls.value,
+      documents: documentUrls.value,
+      merchant_id: "3",
+      model_type: selectedModelInfo.value.type,
+      model_name: selectedModelInfo.value.name
+    }
     
-    // 更新消息数组
-    setMessages(newMessages)
-
-    // 清理输入
+ // 清理输入(移到这里,确保在发送请求前清理)
     await nextTick(() => {
       inputContent.value = ''
       items.value = []
@@ -552,24 +567,12 @@ const handleSubmit = async () => {
       documentUrls.value = []
     })
 
-    // API 请求
     const response = await fetch(`${API_BASE_URL}/api/chat/online/multimodal`, {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json'
       },
-      body: JSON.stringify({
-        message: content,
-        chat_config_id: "17",
-        user_id: 4,
-        session_id: activeConversation.value,
-        source: "pc",
-        image_urls: imageUrls.value,
-        documents: documentUrls.value,
-        merchant_id: "3",
-        model_type: selectedModelInfo.value.type,
-        model_name: selectedModelInfo.value.name
-      })
+      body: JSON.stringify(requestData)
     })
 
     if (!response.ok) {
@@ -580,23 +583,24 @@ const handleSubmit = async () => {
     if (result.code !== 2000) {
       throw new Error(`API returned error code: ${result.code}`)
     }
-    
+
     activeConversation.value = result.session_id
+    
     if (result.choices?.[0]?.message?.content) {
       const aiMessageId = `ai-${Date.now()}`
       const fullMessage = result.choices[0].message.content
 
-      // 使用最新的消息数组
-      const latestMessages = [...messages.value]
-      const updatedMessages = [...latestMessages, {
-        id: aiMessageId,
-        role: 'ai',
-        message: '',
-        status: 'loading'
-      }]
-      setMessages(updatedMessages)
-
-      // 逐字显示
+      // 使用函数形式更新消息,确保基于最新状态
+      setMessages(currentMessages => [
+        ...currentMessages,
+        {
+          id: aiMessageId,
+          role: 'ai',
+          message: '',
+          status: 'loading'
+        }
+      ])
+
       let currentText = ''
       const chars = fullMessage.split('')
 
@@ -604,21 +608,24 @@ const handleSubmit = async () => {
         await new Promise(resolve => setTimeout(resolve, 50))
         currentText += chars[i]
         
-        const progressMessages = messages.value.map(msg =>
-          msg.id === aiMessageId
-            ? { ...msg, message: currentText }
-            : msg
+        // 使用函数形式更新消息
+        setMessages(currentMessages => 
+          currentMessages.map(msg =>
+            msg.id === aiMessageId
+              ? { ...msg, message: currentText }
+              : msg
+          )
         )
-        setMessages(progressMessages)
       }
 
-      // 确保最终状态使用最新的消息数组
-      const finalMessages = messages.value.map(msg =>
-        msg.id === aiMessageId
-          ? { ...msg, message: fullMessage, status: 'success' }
-          : msg
+      // 最终更新使用函数形式
+      setMessages(currentMessages =>
+        currentMessages.map(msg =>
+          msg.id === aiMessageId
+            ? { ...msg, message: fullMessage, status: 'success' }
+            : msg
+        )
       )
-      setMessages(finalMessages)
     }
 
   } catch (error) {
@@ -629,13 +636,13 @@ const handleSubmit = async () => {
   }
 }
 
-// 添加文件上传函数
+// 修改文件上传函数
 const uploadFile = async (file: File) => {
   const formData = new FormData()
   formData.append('file', file)
 
   try {
-    const response = await fetch('http://your-api/upload/file', {
+    const response = await fetch(`${API_BASE_URL}/upload/file`, {
       method: 'POST',
       body: formData
     })
@@ -650,8 +657,10 @@ const uploadFile = async (file: File) => {
     const fileUrl = result.data.fileUrl
     if (file.type.startsWith('image/')) {
       imageUrls.value.push(fileUrl)
+      console.log('Added image URL:', fileUrl, 'Current images:', imageUrls.value)
     } else {
       documentUrls.value.push(fileUrl)
+      console.log('Added document URL:', fileUrl, 'Current documents:', documentUrls.value)
     }
 
     return fileUrl
@@ -682,7 +691,7 @@ const onPromptsItemClick = async (info: any) => {
   }
 }
 
-// 添加文件处理函数
+// 修改文件处理函数
 const handleFileChange = (info: any) => {
   const { fileList } = info
   attachedFiles.value = fileList.map((file: any) => ({
@@ -698,10 +707,12 @@ const handleFileChange = (info: any) => {
       if (file.type?.startsWith('image/')) {
         if (!imageUrls.value.includes(fileUrl)) {
           imageUrls.value.push(fileUrl)
+          console.log('Added image from fileList:', fileUrl)
         }
       } else {
         if (!documentUrls.value.includes(fileUrl)) {
           documentUrls.value.push(fileUrl)
+          console.log('Added document from fileList:', fileUrl)
         }
       }
     }
@@ -732,7 +743,7 @@ const attachmentsNode = computed(() =>
 
 // 添加欢迎页面的计算属性
 const welcomeTitle = computed(() => ({
-  content: 'Hello, I\'m Ant Design X',
+  content: '你好,我是AI助手',
   style: {
     fontSize: '24px',
     fontWeight: 'bold',
@@ -740,7 +751,7 @@ const welcomeTitle = computed(() => ({
   }
 }))
 
-const welcomeDescription = ref('Base on Ant Design, AGI product interface solution, create a better intelligent vision~')
+const welcomeDescription = ref('')
 
 const [message, contextHolder] = messageAnt.useMessage();
 
@@ -767,11 +778,11 @@ const triggerOpen = () => {
 }
 
 const senderSubmit = () => {
-  message.success('Send message successfully!');
+  message.success('消息发送成功!');
 }
 
 const selectFileClick = () => {
-  message.info('Mock select file');
+  message.info('选择文件');
 }
 
 // 确保所有响应式数据都有初始值
@@ -786,7 +797,7 @@ const selectRef = ref()
 
 const senderHeader = computed(() =>
   h(Sender.Header, {
-    title: "Attachments",
+    title: "附件",
     styles: {
       content: {
         padding: 0,
@@ -818,11 +829,11 @@ const senderHeader = computed(() =>
         }
       },
       placeholder: (type: string) => type === 'drop'
-        ? { title: 'Drop file here' }
+        ? { title: '将文件拖放到此处' }
         : {
           icon: h(CloudUploadOutlined),
-          title: 'Upload files',
-          description: 'Click or drag files to this area to upload',
+          title: '上传文件',
+          description: '点击或将文件拖拽到此区域上传',
         },
       getDropContainer: () => senderRef.value?.nativeElement
     })
@@ -843,11 +854,26 @@ const handleInputChange = (value: string) => {
   inputContent.value = value
 }
 
-// 添加清理文件的函数
+// 修改清理文件的函数
 const clearFiles = () => {
+  // 清空文件数组
   attachedFiles.value = []
   imageUrls.value = []
   documentUrls.value = []
+  
+  // 重置Attachments组件的状态
+  if (senderRef.value) {
+    // 尝试访问Attachments组件并重置其状态
+    const attachmentsComponent = senderRef.value.$refs?.attachmentsRef
+    if (attachmentsComponent) {
+      attachmentsComponent.fileList = []
+    }
+  }
+  
+  // 重置header的打开状态
+  open.value = false
+  
+  console.log('Files cleared')
 }
 
 // 在 script setup 中添加滚动逻辑

+ 1 - 0
vite.config.js

@@ -39,6 +39,7 @@ export default defineConfig(({ command, mode }) => {
       extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.vue']
     },
     server: {
+      host: true,
       port: 8003,
       proxy: {
         '/WebSocketConfig/': {

File diff ditekan karena terlalu besar
+ 772 - 4
yarn.lock


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini