pull/1/head
alireza hassani 5 years ago
commit 0d98098acd

1
.gitignore vendored

@ -3,6 +3,7 @@
/storage/*.key
/vendor
/modules
/development/
.env
.phpunit.result.cache
Homestead.json

@ -11,10 +11,10 @@
"php": "^7.1.3",
"fideloper/proxy": "^4.0",
"kalnoy/nestedset": "^5.0",
"laravel/framework": "6.3.*",
"laravel/framework": "6.*",
"laravel/passport": "^7.3",
"laravel/tinker": "^1.0",
"spatie/laravel-medialibrary": "^7.14",
"spatie/laravel-medialibrary": "^7.0.0",
"wm/common": "dev-master",
"wm/core": "dev-master",
"wm/crm": "dev-master",
@ -26,7 +26,8 @@
"fzaninotto/faker": "^1.4",
"mockery/mockery": "^1.0",
"nunomaduro/collision": "^2.0",
"phpunit/phpunit": "^7.0"
"phpunit/phpunit": "^7.0",
"zircote/swagger-php": "^3.0"
},
"config": {
"optimize-autoloader": true,

696
composer.lock generated

File diff suppressed because it is too large Load Diff

@ -64,6 +64,11 @@ return [
'url' => env('AWS_URL'),
],
'media' => [
'driver' => 'local',
'root' => public_path('uploads'),
],
],
];

@ -0,0 +1,156 @@
<?php
return [
/*
* The disk on which to store added files and derived images by default. Choose
* one or more of the disks you've configured in config/filesystems.php.
*/
'disk_name' => env('MEDIA_DISK', 'media'),
/*
* The maximum file size of an item in bytes.
* Adding a larger file will result in an exception.
*/
'max_file_size' => 1024 * 1024 * 10,
/*
* This queue will be used to generate derived and responsive images.
* Leave empty to use the default queue.
*/
'queue_name' => '',
/*
* The fully qualified class name of the media model.
*/
'media_model' => WM\Common\Models\Media::class,
's3' => [
/*
* The domain that should be prepended when generating urls.
*/
'domain' => 'https://'.env('AWS_BUCKET').'.s3.amazonaws.com',
],
'remote' => [
/*
* Any extra headers that should be included when uploading media to
* a remote disk. Even though supported headers may vary between
* different drivers, a sensible default has been provided.
*
* Supported by S3: CacheControl, Expires, StorageClass,
* ServerSideEncryption, Metadata, ACL, ContentEncoding
*/
'extra_headers' => [
'CacheControl' => 'max-age=604800',
],
],
'responsive_images' => [
/*
* This class is responsible for calculating the target widths of the responsive
* images. By default we optimize for filesize and create variations that each are 20%
* smaller than the previous one. More info in the documentation.
*
* https://docs.spatie.be/laravel-medialibrary/v7/advanced-usage/generating-responsive-images
*/
'width_calculator' => Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\FileSizeOptimizedWidthCalculator::class,
/*
* By default rendering media to a responsive image will add some javascript and a tiny placeholder.
* This ensures that the browser can already determine the correct layout.
*/
'use_tiny_placeholders' => true,
/*
* This class will generate the tiny placeholder used for progressive image loading. By default
* the medialibrary will use a tiny blurred jpg image.
*/
'tiny_placeholder_generator' => Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\Blurred::class,
],
/*
* When urls to files get generated, this class will be called. Leave empty
* if your files are stored locally above the site root or on s3.
*/
'url_generator' => null,
/*
* Whether to activate versioning when urls to files get generated.
* When activated, this attaches a ?v=xx query string to the URL.
*/
'version_urls' => false,
/*
* The class that contains the strategy for determining a media file's path.
*/
'path_generator' => null,
/*
* Medialibrary will try to optimize all converted images by removing
* metadata and applying a little bit of compression. These are
* the optimizers that will be used by default.
*/
'image_optimizers' => [
Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [
'--strip-all', // this strips out all text information such as comments and EXIF data
'--all-progressive', // this will make sure the resulting image is a progressive one
],
Spatie\ImageOptimizer\Optimizers\Pngquant::class => [
'--force', // required parameter for this package
],
Spatie\ImageOptimizer\Optimizers\Optipng::class => [
'-i0', // this will result in a non-interlaced, progressive scanned image
'-o2', // this set the optimization level to two (multiple IDAT compression trials)
'-quiet', // required parameter for this package
],
Spatie\ImageOptimizer\Optimizers\Svgo::class => [
'--disable=cleanupIDs', // disabling because it is known to cause troubles
],
Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [
'-b', // required parameter for this package
'-O3', // this produces the slowest but best results
],
],
/*
* These generators will be used to create an image of media files.
*/
'image_generators' => [
Spatie\MediaLibrary\ImageGenerators\FileTypes\Image::class,
Spatie\MediaLibrary\ImageGenerators\FileTypes\Webp::class,
Spatie\MediaLibrary\ImageGenerators\FileTypes\Pdf::class,
Spatie\MediaLibrary\ImageGenerators\FileTypes\Svg::class,
Spatie\MediaLibrary\ImageGenerators\FileTypes\Video::class,
],
/*
* The engine that should perform the image conversions.
* Should be either `gd` or `imagick`.
*/
'image_driver' => 'gd',
/*
* FFMPEG & FFProbe binaries paths, only used if you try to generate video
* thumbnails and have installed the php-ffmpeg/php-ffmpeg composer
* dependency.
*/
'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'),
'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'),
/*
* The path where to store temporary files while performing image conversions.
* If set to null, storage_path('medialibrary/temp') will be used.
*/
'temporary_directory_path' => null,
/*
* Here you can override the class names of the jobs used by this package. Make sure
* your custom jobs extend the ones provided by the package.
*/
'jobs' => [
'perform_conversions' => Spatie\MediaLibrary\Jobs\PerformConversions::class,
'generate_responsive_images' => Spatie\MediaLibrary\Jobs\GenerateResponsiveImages::class,
],
];

@ -0,0 +1,19 @@
{
"compilerOptions": {
"module": "es6",
"target": "es2017",
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"paths": {
"@JS/*": ["./resources/js/*"],
"@Global/*": ["./resources/js/Global/*"],
"@Home/*": ["./resources/js/Home/*"],
"@CRM/*": ["./modules/wm-crm/resources/js/*"],
"@Common/*": ["./modules/wm-common/resources/js/*"],
"@Core/*": ["./modules/wm-core/resources/js/*"],
"@User/*": ["./modules/wm-core/resources/js/Modules/User/*"],
"@Auth/*": ["./modules/wm-core/resources/js/Modules/Authentication/*"]
}
},
"exclude": ["node_modules"]
}

13
package-lock.json generated

@ -3965,6 +3965,11 @@
"integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=",
"dev": true
},
"dropzone": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.5.1.tgz",
"integrity": "sha512-3VduRWLxx9hbVr42QieQN25mx/I61/mRdUSuxAmDGdDqZIN8qtP7tcKMa3KfpJjuGjOJGYYUzzeq6eGDnkzesA=="
},
"duplexer3": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@ -11602,6 +11607,14 @@
"vue-template-compiler": "^2.5.13"
}
},
"vue2-dropzone": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/vue2-dropzone/-/vue2-dropzone-3.6.0.tgz",
"integrity": "sha512-YXC1nCWIZvfa98e/i6h+EshZCkFSxFEh0Sxr9ODfThAPPDVhAzLLlz/4XIx0NGO1QeSy6htwSstte47R7vVhLQ==",
"requires": {
"dropzone": "^5.5.1"
}
},
"vuetify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.1.1.tgz",

@ -41,6 +41,7 @@
"vue-scroll-reveal": "^1.0.11",
"vue-the-mask": "^0.11.1",
"vue-tinymce-editor": "^1.6.2",
"vue2-dropzone": "^3.6.0",
"vuetify": "^2.0.19"
},
"devDependencies": {

@ -1,6 +1,6 @@
{
"/js/vue/Authentication/app.js": "/js/vue/Authentication/app.js?id=819b3d17d481c306f180",
"/js/vue/Home/app.js": "/js/vue/Home/app.js?id=039099abb3e02beeaee8",
"/js/vue/Modules/CRM/app.js": "/js/vue/Modules/CRM/app.js?id=690f40fe1935f237b5e5",
"/js/vue/User/app.js": "/js/vue/User/app.js?id=bbe2a8c4869dfd0e6a86"
"/js/vue/Authentication/app.js": "/js/vue/Authentication/app.js?id=5ecd9d63d69524aa5d59",
"/js/vue/Home/app.js": "/js/vue/Home/app.js?id=7919d02b13503006b63e",
"/js/vue/Modules/CRM/app.js": "/js/vue/Modules/CRM/app.js?id=847452875db92e8b7b3b",
"/js/vue/User/app.js": "/js/vue/User/app.js?id=18aa487b7bff671e9e13"
}

@ -2,17 +2,17 @@
<div class="WM-Checkbox c-toggle-hide RTL WM-Align-R">
<input
type="checkbox"
:id="ItemID"
:id="rand"
class="c-check"
:value="ItemID"
:value="valueSelected"
v-model="values"
@change="changeValue"
/>
<label :for="ItemID">
<label :for="rand">
<span class="inc"></span>
<span class="check"></span>
<span class="box"></span>
{{ ItemText }}
{{ showText }}
</label>
</div>
</template>
@ -20,33 +20,84 @@
<script>
export default {
props: {
ItemID: { default: "Checkbox" },
ItemText: { default: " مقدار پیش فرض " },
itemValue: { default: null },
itemSlug: { default: 'id' },
itemText: { default: null },
text: { default: " " },
item: { default: {} },
color: { default: "Red" },
value: { type: Array }
},
data: function() {
return {
IconClass: "WMi-" + this.Icon,
values: this.value
rand: Math.random(),
values: this.computedValues(this.value)
};
},
computed: {
valueSelected() {
if (typeof this.item == 'object') {
if (this.itemValue) {
return this.item[this.itemValue];
} else {
return this.item[this.itemSlug];
}
} else {
return this.item;
}
},
showText() {
if (this.itemText) {
return this.item[this.itemText];
}
return this.text;
},
},
methods: {
changeValue($event) {
if (this.value) {
if ($event.target.checked) {
this.value.push(this.ItemID);
if (this.itemValue) {
this.value.push(this.valueSelected);
} else {
this.value.push(this.item);
}
} else {
let index = this.value.findIndex(x => x == this.ItemID);
if (typeof this.item == 'object' && !this.itemValue) {
var index = this.value.findIndex(
x => x[this.itemSlug] == this.item[this.itemSlug]
);
} else {
var index = this.value.findIndex(
x => x == this.valueSelected
);
}
this.value.splice(index, 1);
}
}
this.$emit("change", this.item, $event.target.checked);
},
computedValues(value) {
if (Array.isArray(value)) {
let newArray = [];
for (const val of value) {
if (typeof val == "object") {
newArray.push(val[this.itemSlug]);
} else {
newArray.push(val);
}
}
return newArray;
} else {
return value;
}
}
},
watch: {
value(value) {
this.values = value;
}
this.values = this.computedValues(value);
},
}
};
</script>

@ -0,0 +1,66 @@
<template>
<div>
<vue-dropzone ref="myVueDropzone" id="dropzone" :destroyDropzone="false" @vdropzone-sending="setParams" @vdropzone-removed-file="removeFile" :options="dropzoneOptions" @vdropzone-success="responseSuccess"></vue-dropzone>
</div>
</template>
<script>
import vue2Dropzone from 'vue2-dropzone'
import { TokenService } from '@Global/services/storage.services'
import commonState from '@Global/store/modules/common/state';
import { url } from '@Common/mixins/urls';
import axios from 'axios';
import 'vue2-dropzone/dist/vue2Dropzone.min.css'
export default {
props: {
defaultMessage: { default: "<i class='fa fa-cloud-upload'></i>آپلود فایل" },
files: {default:() => ([])},
batch_id: { required: true, type: String }
},
components: {
vueDropzone: vue2Dropzone
},
data() {
return {
dropzoneOptions: {
url: url('storeFile'),
thumbnailWidth: 200,
headers: { "Authorization": `Bearer ${TokenService.getToken()}`, "Module": `${commonState.current_module}` },
addRemoveLinks: true,
dictDefaultMessage: this.defaultMessage,
sendingMultiple: true,
},
}
},
computed: {
batchId() {
return this.batch_id;
},
},
methods: {
responseSuccess(file, response) {
if (response.data && response.data.id) {
file['id'] = response.data.id;
}
},
removeFile(file, error, xhr) {
if(this.dropzoneOptions.removeType == "server") {
axios.delete(url('deleteFile', {file: file.id}));
}
},
manuallyLoadFiles(files) { //file =[ {size: 123, name: "Icon", type: "image/png", url: "https://myvizo.com/img/logo_sm.png"}]
for (const file of files) {
this.$refs.myVueDropzone.manuallyAddFile(file, file.url);
}
},
setParams(file, xhr, formData) {
formData.append('batch_id', this.batchId);
},
},
watch: {
files(files) {
this.manuallyLoadFiles(files);
}
},
};
</script>

@ -3,14 +3,11 @@ var CommingSoonArray = [
"discount",
"transaction",
"email",
// "sms",
"prescription",
"user_sms",
"crm-setting",
// "crm-client-filter",
"crm-statistics",
// "user-list-filter",
];
const commingSoon = {
methods: {

@ -234,6 +234,10 @@ a:hover {
border-radius: 5px;
}
.PreFormatted {
white-space: pre;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,

@ -10,7 +10,7 @@ const createFilterObject = filters => {
}
}
}
return filterObject;
return {filters: filterObject};
};
window['between'] = function (filter) {
var value = null;

@ -0,0 +1,10 @@
const makeid = function makeid(length) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
export { makeid };

@ -18,7 +18,7 @@
></wm-tile>
</a>
</v-layout>
<router-link v-if="getAuthUser.is_owner == 'true'" :to="{name: 'AddModule'}">
<router-link v-if="getAuthUser.is_owner == 'true' || hostname == originHostName" :to="{name: 'AddModule'}">
<v-btn large fab color="cyan" fixed bottom left dark style="left:5%">
<v-icon dark>fas fa-plus</v-icon>
</v-btn>
@ -31,8 +31,12 @@
<script>
import Tile from "@Global/components/Tiles/Tile";
import { mapGetters, mapActions } from "vuex";
import routes from '@Global/utils/common/routes';
export default {
data: () => ({}),
data: () => ({
hostname : window.location.hostname,
originHostName : routes.originHostName()
}),
components: {
"wm-tile": Tile,
},
@ -45,6 +49,7 @@ export default {
},
created() {
this.loadModules({ home_page: true });
}
};
</script>

Loading…
Cancel
Save